<!doctype html>
<head>
  <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
  <meta name="viewport" content="width=device-width, initial-scale=1, minimum-scale=1" />

    <title>nimporter API documentation</title>
    <meta name="description" content="Contains classes to compile Python-Nim Extension modules, import those modules,
and generate excepti..." />

  <link href='http://fonts.googleapis.com/css?family=Source+Sans+Pro:400,300' rel='stylesheet' type='text/css'>
  
  <style type="text/css">
  
* {
  box-sizing: border-box;
}
/*! normalize.css v1.1.1 | MIT License | git.io/normalize */

/* ==========================================================================
   HTML5 display definitions
   ========================================================================== */

/**
 * Correct `block` display not defined in IE 6/7/8/9 and Firefox 3.
 */

article,
aside,
details,
figcaption,
figure,
footer,
header,
hgroup,
main,
nav,
section,
summary {
    display: block;
}

/**
 * Correct `inline-block` display not defined in IE 6/7/8/9 and Firefox 3.
 */

audio,
canvas,
video {
    display: inline-block;
    *display: inline;
    *zoom: 1;
}

/**
 * Prevent modern browsers from displaying `audio` without controls.
 * Remove excess height in iOS 5 devices.
 */

audio:not([controls]) {
    display: none;
    height: 0;
}

/**
 * Address styling not present in IE 7/8/9, Firefox 3, and Safari 4.
 * Known issue: no IE 6 support.
 */

[hidden] {
    display: none;
}

/* ==========================================================================
   Base
   ========================================================================== */

/**
 * 1. Prevent system color scheme's background color being used in Firefox, IE,
 *    and Opera.
 * 2. Prevent system color scheme's text color being used in Firefox, IE, and
 *    Opera.
 * 3. Correct text resizing oddly in IE 6/7 when body `font-size` is set using
 *    `em` units.
 * 4. Prevent iOS text size adjust after orientation change, without disabling
 *    user zoom.
 */

html {
    background: #fff; /* 1 */
    color: #000; /* 2 */
    font-size: 100%; /* 3 */
    -webkit-text-size-adjust: 100%; /* 4 */
    -ms-text-size-adjust: 100%; /* 4 */
}

/**
 * Address `font-family` inconsistency between `textarea` and other form
 * elements.
 */

html,
button,
input,
select,
textarea {
    font-family: sans-serif;
}

/**
 * Address margins handled incorrectly in IE 6/7.
 */

body {
    margin: 0;
}

/* ==========================================================================
   Links
   ========================================================================== */

/**
 * Address `outline` inconsistency between Chrome and other browsers.
 */

a:focus {
    outline: thin dotted;
}

/**
 * Improve readability when focused and also mouse hovered in all browsers.
 */

a:active,
a:hover {
    outline: 0;
}

/* ==========================================================================
   Typography
   ========================================================================== */

/**
 * Address font sizes and margins set differently in IE 6/7.
 * Address font sizes within `section` and `article` in Firefox 4+, Safari 5,
 * and Chrome.
 */

h1 {
    font-size: 2em;
    margin: 0.67em 0;
}

h2 {
    font-size: 1.5em;
    margin: 0.83em 0;
}

h3 {
    font-size: 1.17em;
    margin: 1em 0;
}

h4 {
    font-size: 1em;
    margin: 1.33em 0;
}

h5 {
    font-size: 0.83em;
    margin: 1.67em 0;
}

h6 {
    font-size: 0.67em;
    margin: 2.33em 0;
}

/**
 * Address styling not present in IE 7/8/9, Safari 5, and Chrome.
 */

abbr[title] {
    border-bottom: 1px dotted;
}

/**
 * Address style set to `bolder` in Firefox 3+, Safari 4/5, and Chrome.
 */

b,
strong {
    font-weight: bold;
}

blockquote {
    margin: 1em 40px;
}

/**
 * Address styling not present in Safari 5 and Chrome.
 */

dfn {
    font-style: italic;
}

/**
 * Address differences between Firefox and other browsers.
 * Known issue: no IE 6/7 normalization.
 */

hr {
    -moz-box-sizing: content-box;
    box-sizing: content-box;
    height: 0;
}

/**
 * Address styling not present in IE 6/7/8/9.
 */

mark {
    background: #ff0;
    color: #000;
}

/**
 * Address margins set differently in IE 6/7.
 */

p,
pre {
    margin: 1em 0;
}

/**
 * Correct font family set oddly in IE 6, Safari 4/5, and Chrome.
 */

code,
kbd,
pre,
samp {
    font-family: monospace, serif;
    _font-family: 'courier new', monospace;
    font-size: 1em;
}

/**
 * Improve readability of pre-formatted text in all browsers.
 */

pre {
    white-space: pre;
    white-space: pre-wrap;
    word-wrap: break-word;
}

/**
 * Address CSS quotes not supported in IE 6/7.
 */

q {
    quotes: none;
}

/**
 * Address `quotes` property not supported in Safari 4.
 */

q:before,
q:after {
    content: '';
    content: none;
}

/**
 * Address inconsistent and variable font size in all browsers.
 */

small {
    font-size: 80%;
}

/**
 * Prevent `sub` and `sup` affecting `line-height` in all browsers.
 */

sub,
sup {
    font-size: 75%;
    line-height: 0;
    position: relative;
    vertical-align: baseline;
}

sup {
    top: -0.5em;
}

sub {
    bottom: -0.25em;
}

/* ==========================================================================
   Lists
   ========================================================================== */

/**
 * Address margins set differently in IE 6/7.
 */

dl,
menu,
ol,
ul {
    margin: 1em 0;
}

dd {
    margin: 0 0 0 40px;
}

/**
 * Address paddings set differently in IE 6/7.
 */

menu,
ol,
ul {
    padding: 0 0 0 40px;
}

/**
 * Correct list images handled incorrectly in IE 7.
 */

nav ul,
nav ol {
    list-style: none;
    list-style-image: none;
}

/* ==========================================================================
   Embedded content
   ========================================================================== */

/**
 * 1. Remove border when inside `a` element in IE 6/7/8/9 and Firefox 3.
 * 2. Improve image quality when scaled in IE 7.
 */

img {
    border: 0; /* 1 */
    -ms-interpolation-mode: bicubic; /* 2 */
}

/**
 * Correct overflow displayed oddly in IE 9.
 */

svg:not(:root) {
    overflow: hidden;
}

/* ==========================================================================
   Figures
   ========================================================================== */

/**
 * Address margin not present in IE 6/7/8/9, Safari 5, and Opera 11.
 */

figure {
    margin: 0;
}

/* ==========================================================================
   Forms
   ========================================================================== */

/**
 * Correct margin displayed oddly in IE 6/7.
 */

form {
    margin: 0;
}

/**
 * Define consistent border, margin, and padding.
 */

fieldset {
    border: 1px solid #c0c0c0;
    margin: 0 2px;
    padding: 0.35em 0.625em 0.75em;
}

/**
 * 1. Correct color not being inherited in IE 6/7/8/9.
 * 2. Correct text not wrapping in Firefox 3.
 * 3. Correct alignment displayed oddly in IE 6/7.
 */

legend {
    border: 0; /* 1 */
    padding: 0;
    white-space: normal; /* 2 */
    *margin-left: -7px; /* 3 */
}

/**
 * 1. Correct font size not being inherited in all browsers.
 * 2. Address margins set differently in IE 6/7, Firefox 3+, Safari 5,
 *    and Chrome.
 * 3. Improve appearance and consistency in all browsers.
 */

button,
input,
select,
textarea {
    font-size: 100%; /* 1 */
    margin: 0; /* 2 */
    vertical-align: baseline; /* 3 */
    *vertical-align: middle; /* 3 */
}

/**
 * Address Firefox 3+ setting `line-height` on `input` using `!important` in
 * the UA stylesheet.
 */

button,
input {
    line-height: normal;
}

/**
 * Address inconsistent `text-transform` inheritance for `button` and `select`.
 * All other form control elements do not inherit `text-transform` values.
 * Correct `button` style inheritance in Chrome, Safari 5+, and IE 6+.
 * Correct `select` style inheritance in Firefox 4+ and Opera.
 */

button,
select {
    text-transform: none;
}

/**
 * 1. Avoid the WebKit bug in Android 4.0.* where (2) destroys native `audio`
 *    and `video` controls.
 * 2. Correct inability to style clickable `input` types in iOS.
 * 3. Improve usability and consistency of cursor style between image-type
 *    `input` and others.
 * 4. Remove inner spacing in IE 7 without affecting normal text inputs.
 *    Known issue: inner spacing remains in IE 6.
 */

button,
html input[type="button"], /* 1 */
input[type="reset"],
input[type="submit"] {
    -webkit-appearance: button; /* 2 */
    cursor: pointer; /* 3 */
    *overflow: visible;  /* 4 */
}

/**
 * Re-set default cursor for disabled elements.
 */

button[disabled],
html input[disabled] {
    cursor: default;
}

/**
 * 1. Address box sizing set to content-box in IE 8/9.
 * 2. Remove excess padding in IE 8/9.
 * 3. Remove excess padding in IE 7.
 *    Known issue: excess padding remains in IE 6.
 */

input[type="checkbox"],
input[type="radio"] {
    box-sizing: border-box; /* 1 */
    padding: 0; /* 2 */
    *height: 13px; /* 3 */
    *width: 13px; /* 3 */
}

/**
 * 1. Address `appearance` set to `searchfield` in Safari 5 and Chrome.
 * 2. Address `box-sizing` set to `border-box` in Safari 5 and Chrome
 *    (include `-moz` to future-proof).
 */

input[type="search"] {
    -webkit-appearance: textfield; /* 1 */
    -moz-box-sizing: content-box;
    -webkit-box-sizing: content-box; /* 2 */
    box-sizing: content-box;
}

/**
 * Remove inner padding and search cancel button in Safari 5 and Chrome
 * on OS X.
 */

input[type="search"]::-webkit-search-cancel-button,
input[type="search"]::-webkit-search-decoration {
    -webkit-appearance: none;
}

/**
 * Remove inner padding and border in Firefox 3+.
 */

button::-moz-focus-inner,
input::-moz-focus-inner {
    border: 0;
    padding: 0;
}

/**
 * 1. Remove default vertical scrollbar in IE 6/7/8/9.
 * 2. Improve readability and alignment in all browsers.
 */

textarea {
    overflow: auto; /* 1 */
    vertical-align: top; /* 2 */
}

/* ==========================================================================
   Tables
   ========================================================================== */

/**
 * Remove most spacing between table cells.
 */

table {
    border-collapse: collapse;
    border-spacing: 0;
}

  </style>

  <style type="text/css">
  
  html, body {
    margin: 0;
    padding: 0;
    min-height: 100%;
  }
  body {
    background: #fff;
    font-family: "Source Sans Pro", "Helvetica Neueue", Helvetica, sans;
    font-weight: 300;
    font-size: 16px;
    line-height: 1.6em;
  }
  #content {
    width: 70%;
    max-width: 850px;
    float: left;
    padding: 30px 60px;
    border-left: 1px solid #ddd;
  }
  #sidebar {
    width: 25%;
    float: left;
    padding: 30px;
    overflow: hidden;
  }
  #nav {
    font-size: 130%;
    margin: 0 0 15px 0;
  }

  #top {
    display: block;
    position: fixed;
    bottom: 5px;
    left: 5px;
    font-size: .85em;
    text-transform: uppercase;
  }

  #footer {
    font-size: .75em;
    padding: 5px 30px;
    border-top: 1px solid #ddd;
    text-align: right;
  }
    #footer p {
      margin: 0 0 0 30px;
      display: inline-block;
    }

  h1, h2, h3, h4, h5 {
    font-weight: 300;
  }
  h1 {
    font-size: 2.5em;
    line-height: 1.1em;
    margin: 0 0 .50em 0;
  }

  h2 {
    font-size: 1.75em;
    margin: 1em 0 .50em 0;
  }

  h3 {
    margin: 25px 0 10px 0;
  }

  h4 {
    margin: 0;
    font-size: 105%;
  }

  a {
    color: #058;
    text-decoration: none;
    transition: color .3s ease-in-out;
  }

  a:hover {
    color: #e08524;
    transition: color .3s ease-in-out;
  }

  pre, code, .mono, .name {
    font-family: "Ubuntu Mono", "Cousine", "DejaVu Sans Mono", monospace;
  }

  .title .name {
    font-weight: bold;
  }
  .section-title {
    margin-top: 2em;
  }
  .ident {
    color: #900;
  }

  code {
    background: #f9f9f9;
  } 

  pre {
    background: #fefefe;
    border: 1px solid #ddd;
    box-shadow: 2px 2px 0 #f3f3f3;
    margin: 0 30px;
    padding: 15px 30px;
  }

  .codehilite {
    margin: 0 30px 10px 30px;
  }

    .codehilite pre {
      margin: 0;
    }
    .codehilite .err { background: #ff3300; color: #fff !important; } 

  table#module-list {
    font-size: 110%;
  }

    table#module-list tr td:first-child {
      padding-right: 10px;
      white-space: nowrap;
    }

    table#module-list td {
      vertical-align: top;
      padding-bottom: 8px;
    }

      table#module-list td p {
        margin: 0 0 7px 0;
      }

  .def {
    display: table;
  }

    .def p {
      display: table-cell;
      vertical-align: top;
      text-align: left;
    }

    .def p:first-child {
      white-space: nowrap;
    }

    .def p:last-child {
      width: 100%;
    }


  #index {
    list-style-type: none;
    margin: 0;
    padding: 0;
  }
    ul#index .class_name {
      /* font-size: 110%; */
      font-weight: bold;
    }
    #index ul {
      margin: 0;
    }

  .item {
    margin: 0 0 15px 0;
  }

    .item .class {
      margin: 0 0 25px 30px;
    }

      .item .class ul.class_list {
        margin: 0 0 20px 0;
      }

    .item .name {
      background: #fafafa;
      margin: 0;
      font-weight: bold;
      padding: 5px 10px;
      border-radius: 3px;
      display: inline-block;
      min-width: 40%;
    }
      .item .name:hover {
        background: #f6f6f6;
      }

    .item .empty_desc {
      margin: 0 0 5px 0;
      padding: 0;
    }

    .item .inheritance {
      margin: 3px 0 0 30px;
    }

    .item .inherited {
      color: #666;
    }

    .item .desc {
      padding: 0 8px;
      margin: 0;
    }

      .item .desc p {
        margin: 0 0 10px 0;
      }

    .source_cont {
      margin: 0;
      padding: 0;
    }

    .source_link a {
      background: #ffc300;
      font-weight: 400;
      font-size: .75em;
      text-transform: uppercase;
      color: #fff;
      text-shadow: 1px 1px 0 #f4b700;
      
      padding: 3px 8px;
      border-radius: 2px;
      transition: background .3s ease-in-out;
    }
      .source_link a:hover {
        background: #FF7200;
        text-shadow: none;
        transition: background .3s ease-in-out;
      }

    .source {
      display: none;
      max-height: 600px;
      overflow-y: scroll;
      margin-bottom: 15px;
    }

      .source .codehilite {
        margin: 0;
      }

  .desc h1, .desc h2, .desc h3 {
    font-size: 100% !important;
  }
  .clear {
    clear: both;
  }

  @media all and (max-width: 950px) {
    #sidebar {
      width: 35%;
    }
    #content {
      width: 65%;
    }
  }
  @media all and (max-width: 650px) {
    #top {
      display: none;
    }
    #sidebar {
      float: none;
      width: auto;
    }
    #content {
      float: none;
      width: auto;
      padding: 30px;
    }

    #index ul {
      padding: 0;
      margin-bottom: 15px;
    }
    #index ul li {
      display: inline-block;
      margin-right: 30px;
    }
    #footer {
      text-align: left;
    }
    #footer p {
      display: block;
      margin: inherit;
    }
  }

  /*****************************/

  </style>

  <style type="text/css">
  .codehilite .hll { background-color: #ffffcc }
.codehilite  { background: #f8f8f8; }
.codehilite .c { color: #408080; font-style: italic } /* Comment */
.codehilite .err { border: 1px solid #FF0000 } /* Error */
.codehilite .k { color: #008000; font-weight: bold } /* Keyword */
.codehilite .o { color: #666666 } /* Operator */
.codehilite .ch { color: #408080; font-style: italic } /* Comment.Hashbang */
.codehilite .cm { color: #408080; font-style: italic } /* Comment.Multiline */
.codehilite .cp { color: #BC7A00 } /* Comment.Preproc */
.codehilite .cpf { color: #408080; font-style: italic } /* Comment.PreprocFile */
.codehilite .c1 { color: #408080; font-style: italic } /* Comment.Single */
.codehilite .cs { color: #408080; font-style: italic } /* Comment.Special */
.codehilite .gd { color: #A00000 } /* Generic.Deleted */
.codehilite .ge { font-style: italic } /* Generic.Emph */
.codehilite .gr { color: #FF0000 } /* Generic.Error */
.codehilite .gh { color: #000080; font-weight: bold } /* Generic.Heading */
.codehilite .gi { color: #00A000 } /* Generic.Inserted */
.codehilite .go { color: #888888 } /* Generic.Output */
.codehilite .gp { color: #000080; font-weight: bold } /* Generic.Prompt */
.codehilite .gs { font-weight: bold } /* Generic.Strong */
.codehilite .gu { color: #800080; font-weight: bold } /* Generic.Subheading */
.codehilite .gt { color: #0044DD } /* Generic.Traceback */
.codehilite .kc { color: #008000; font-weight: bold } /* Keyword.Constant */
.codehilite .kd { color: #008000; font-weight: bold } /* Keyword.Declaration */
.codehilite .kn { color: #008000; font-weight: bold } /* Keyword.Namespace */
.codehilite .kp { color: #008000 } /* Keyword.Pseudo */
.codehilite .kr { color: #008000; font-weight: bold } /* Keyword.Reserved */
.codehilite .kt { color: #B00040 } /* Keyword.Type */
.codehilite .m { color: #666666 } /* Literal.Number */
.codehilite .s { color: #BA2121 } /* Literal.String */
.codehilite .na { color: #7D9029 } /* Name.Attribute */
.codehilite .nb { color: #008000 } /* Name.Builtin */
.codehilite .nc { color: #0000FF; font-weight: bold } /* Name.Class */
.codehilite .no { color: #880000 } /* Name.Constant */
.codehilite .nd { color: #AA22FF } /* Name.Decorator */
.codehilite .ni { color: #999999; font-weight: bold } /* Name.Entity */
.codehilite .ne { color: #D2413A; font-weight: bold } /* Name.Exception */
.codehilite .nf { color: #0000FF } /* Name.Function */
.codehilite .nl { color: #A0A000 } /* Name.Label */
.codehilite .nn { color: #0000FF; font-weight: bold } /* Name.Namespace */
.codehilite .nt { color: #008000; font-weight: bold } /* Name.Tag */
.codehilite .nv { color: #19177C } /* Name.Variable */
.codehilite .ow { color: #AA22FF; font-weight: bold } /* Operator.Word */
.codehilite .w { color: #bbbbbb } /* Text.Whitespace */
.codehilite .mb { color: #666666 } /* Literal.Number.Bin */
.codehilite .mf { color: #666666 } /* Literal.Number.Float */
.codehilite .mh { color: #666666 } /* Literal.Number.Hex */
.codehilite .mi { color: #666666 } /* Literal.Number.Integer */
.codehilite .mo { color: #666666 } /* Literal.Number.Oct */
.codehilite .sa { color: #BA2121 } /* Literal.String.Affix */
.codehilite .sb { color: #BA2121 } /* Literal.String.Backtick */
.codehilite .sc { color: #BA2121 } /* Literal.String.Char */
.codehilite .dl { color: #BA2121 } /* Literal.String.Delimiter */
.codehilite .sd { color: #BA2121; font-style: italic } /* Literal.String.Doc */
.codehilite .s2 { color: #BA2121 } /* Literal.String.Double */
.codehilite .se { color: #BB6622; font-weight: bold } /* Literal.String.Escape */
.codehilite .sh { color: #BA2121 } /* Literal.String.Heredoc */
.codehilite .si { color: #BB6688; font-weight: bold } /* Literal.String.Interpol */
.codehilite .sx { color: #008000 } /* Literal.String.Other */
.codehilite .sr { color: #BB6688 } /* Literal.String.Regex */
.codehilite .s1 { color: #BA2121 } /* Literal.String.Single */
.codehilite .ss { color: #19177C } /* Literal.String.Symbol */
.codehilite .bp { color: #008000 } /* Name.Builtin.Pseudo */
.codehilite .fm { color: #0000FF } /* Name.Function.Magic */
.codehilite .vc { color: #19177C } /* Name.Variable.Class */
.codehilite .vg { color: #19177C } /* Name.Variable.Global */
.codehilite .vi { color: #19177C } /* Name.Variable.Instance */
.codehilite .vm { color: #19177C } /* Name.Variable.Magic */
.codehilite .il { color: #666666 } /* Literal.Number.Integer.Long */
  </style>

  <style type="text/css">
  
/* ==========================================================================
   EXAMPLE Media Queries for Responsive Design.
   These examples override the primary ('mobile first') styles.
   Modify as content requires.
   ========================================================================== */

@media only screen and (min-width: 35em) {
    /* Style adjustments for viewports that meet the condition */
}

@media print,
       (-o-min-device-pixel-ratio: 5/4),
       (-webkit-min-device-pixel-ratio: 1.25),
       (min-resolution: 120dpi) {
    /* Style adjustments for high resolution devices */
}

/* ==========================================================================
   Print styles.
   Inlined to avoid required HTTP connection: h5bp.com/r
   ========================================================================== */

@media print {
    * {
        background: transparent !important;
        color: #000 !important; /* Black prints faster: h5bp.com/s */
        box-shadow: none !important;
        text-shadow: none !important;
    }

    a,
    a:visited {
        text-decoration: underline;
    }

    a[href]:after {
        content: " (" attr(href) ")";
    }

    abbr[title]:after {
        content: " (" attr(title) ")";
    }

    /*
     * Don't show links for images, or javascript/internal links
     */

    .ir a:after,
    a[href^="javascript:"]:after,
    a[href^="#"]:after {
        content: "";
    }

    pre,
    blockquote {
        border: 1px solid #999;
        page-break-inside: avoid;
    }

    thead {
        display: table-header-group; /* h5bp.com/t */
    }

    tr,
    img {
        page-break-inside: avoid;
    }

    img {
        max-width: 100% !important;
    }

    @page {
        margin: 0.5cm;
    }

    p,
    h2,
    h3 {
        orphans: 3;
        widows: 3;
    }

    h2,
    h3 {
        page-break-after: avoid;
    }
}

  </style>

  <script type="text/javascript">
  function toggle(id, $link) {
    $node = document.getElementById(id);
    if (!$node)
    return;
    if (!$node.style.display || $node.style.display == 'none') {
    $node.style.display = 'block';
    $link.innerHTML = 'Hide source &nequiv;';
    } else {
    $node.style.display = 'none';
    $link.innerHTML = 'Show source &equiv;';
    }
  }
  </script>
</head>
<body>
<a href="#" id="top">Top</a>

<div id="container">
    
  
  <div id="sidebar">
    <h1>Index</h1>
    <ul id="index">

    <li class="set"><h3><a href="#header-functions">Functions</a></h3>
      
  <ul>
    <li class="mono"><a href="#nimporter.build_nim_extensions">build_nim_extensions</a></li>
    <li class="mono"><a href="#nimporter.cd">cd</a></li>
    <li class="mono"><a href="#nimporter.register_importer">register_importer</a></li>
  </ul>

    </li>

    <li class="set"><h3><a href="#header-classes">Classes</a></h3>
      <ul>
        <li class="mono">
        <span class="class_name"><a href="#nimporter.NimCompileException">NimCompileException</a></span>
        
          
  <ul>
    <li class="mono"><a href="#nimporter.NimCompileException.__init__">__init__</a></li>
  </ul>

        </li>
        <li class="mono">
        <span class="class_name"><a href="#nimporter.NimCompiler">NimCompiler</a></span>
        
          
  <ul>
    <li class="mono"><a href="#nimporter.NimCompiler.get_import_prefix">get_import_prefix</a></li>
    <li class="mono"><a href="#nimporter.NimCompiler.build_artifact">build_artifact</a></li>
    <li class="mono"><a href="#nimporter.NimCompiler.compile_nim_code">compile_nim_code</a></li>
    <li class="mono"><a href="#nimporter.NimCompiler.compile_nim_extension">compile_nim_extension</a></li>
    <li class="mono"><a href="#nimporter.NimCompiler.ensure_nimpy">ensure_nimpy</a></li>
    <li class="mono"><a href="#nimporter.NimCompiler.find_nim_std_lib">find_nim_std_lib</a></li>
    <li class="mono"><a href="#nimporter.NimCompiler.get_switches">get_switches</a></li>
    <li class="mono"><a href="#nimporter.NimCompiler.invoke_compiler">invoke_compiler</a></li>
    <li class="mono"><a href="#nimporter.NimCompiler.pycache_dir">pycache_dir</a></li>
  </ul>

        </li>
        <li class="mono">
        <span class="class_name"><a href="#nimporter.NimInvokeException">NimInvokeException</a></span>
        
          
  <ul>
    <li class="mono"><a href="#nimporter.NimInvokeException.__init__">__init__</a></li>
    <li class="mono"><a href="#nimporter.NimInvokeException.get_output">get_output</a></li>
  </ul>

        </li>
        <li class="mono">
        <span class="class_name"><a href="#nimporter.NimLibImporter">NimLibImporter</a></span>
        
          
  <ul>
    <li class="mono"><a href="#nimporter.NimLibImporter.find_spec">find_spec</a></li>
  </ul>

        </li>
        <li class="mono">
        <span class="class_name"><a href="#nimporter.NimModImporter">NimModImporter</a></span>
        
          
  <ul>
    <li class="mono"><a href="#nimporter.NimModImporter.find_spec">find_spec</a></li>
  </ul>

        </li>
        <li class="mono">
        <span class="class_name"><a href="#nimporter.Nimporter">Nimporter</a></span>
        
          
  <ul>
    <li class="mono"><a href="#nimporter.Nimporter.hash_file">hash_file</a></li>
    <li class="mono"><a href="#nimporter.Nimporter.build_nim_extensions">build_nim_extensions</a></li>
    <li class="mono"><a href="#nimporter.Nimporter.check_nim_extensions">check_nim_extensions</a></li>
    <li class="mono"><a href="#nimporter.Nimporter.get_hash">get_hash</a></li>
    <li class="mono"><a href="#nimporter.Nimporter.get_nim_extensions">get_nim_extensions</a></li>
    <li class="mono"><a href="#nimporter.Nimporter.hash_changed">hash_changed</a></li>
    <li class="mono"><a href="#nimporter.Nimporter.hash_filename">hash_filename</a></li>
    <li class="mono"><a href="#nimporter.Nimporter.import_nim_code">import_nim_code</a></li>
    <li class="mono"><a href="#nimporter.Nimporter.import_nim_module">import_nim_module</a></li>
    <li class="mono"><a href="#nimporter.Nimporter.is_built">is_built</a></li>
    <li class="mono"><a href="#nimporter.Nimporter.is_cache">is_cache</a></li>
    <li class="mono"><a href="#nimporter.Nimporter.is_hashed">is_hashed</a></li>
    <li class="mono"><a href="#nimporter.Nimporter.should_compile">should_compile</a></li>
    <li class="mono"><a href="#nimporter.Nimporter.update_hash">update_hash</a></li>
  </ul>

        </li>
        <li class="mono">
        <span class="class_name"><a href="#nimporter.NimporterException">NimporterException</a></span>
        
        </li>
      </ul>
    </li>

    </ul>
  </div>

    <article id="content">
      
  

  


  <header id="section-intro">
  <h1 class="title"><span class="name">nimporter</span> module</h1>
  <p>Contains classes to compile Python-Nim Extension modules, import those modules,
and generate exceptions where appropriate.</p>
<p>In addition, distribution of libraries using Nim code via Nimporter can easily
compile those modules to C and bundle into a source or binary distribution so
users of the library don't have to install a Nim compiler.</p>
  
  <p class="source_link"><a href="javascript:void(0);" onclick="toggle('source-nimporter', this);">Show source &equiv;</a></p>
  <div id="source-nimporter" class="source">
    <div class="codehilite"><pre><span></span><span class="sd">&quot;&quot;&quot;</span>
<span class="sd">Contains classes to compile Python-Nim Extension modules, import those modules,</span>
<span class="sd">and generate exceptions where appropriate.</span>

<span class="sd">In addition, distribution of libraries using Nim code via Nimporter can easily</span>
<span class="sd">compile those modules to C and bundle into a source or binary distribution so</span>
<span class="sd">users of the library don&#39;t have to install a Nim compiler.</span>
<span class="sd">&quot;&quot;&quot;</span>

<span class="kn">import</span> <span class="nn">sys</span><span class="o">,</span> <span class="nn">os</span><span class="o">,</span> <span class="nn">subprocess</span><span class="o">,</span> <span class="nn">importlib</span><span class="o">,</span> <span class="nn">hashlib</span><span class="o">,</span> <span class="nn">tempfile</span><span class="o">,</span> <span class="nn">shutil</span>
<span class="kn">from</span> <span class="nn">pathlib</span> <span class="kn">import</span> <span class="n">Path</span>
<span class="kn">from</span> <span class="nn">contextlib</span> <span class="kn">import</span> <span class="n">contextmanager</span>
<span class="kn">from</span> <span class="nn">setuptools</span> <span class="kn">import</span> <span class="n">Extension</span>

<span class="c1"># NOTE(pebaz): https://stackoverflow.com/questions/39660934/error-when-using-importlib-util-to-check-for-library/39661116</span>
<span class="kn">from</span> <span class="nn">importlib</span> <span class="kn">import</span> <span class="n">util</span>


<span class="nd">@contextmanager</span>
<span class="k">def</span> <span class="nf">cd</span><span class="p">(</span><span class="n">path</span><span class="p">):</span>
    <span class="s2">&quot;Convenience function to step in and out of a directory temporarily.&quot;</span>
    <span class="n">cwd</span> <span class="o">=</span> <span class="n">os</span><span class="o">.</span><span class="n">getcwd</span><span class="p">()</span>
    <span class="n">os</span><span class="o">.</span><span class="n">chdir</span><span class="p">(</span><span class="n">path</span><span class="p">)</span>
    <span class="k">try</span><span class="p">:</span>
        <span class="k">yield</span> <span class="n">path</span>
    <span class="k">finally</span><span class="p">:</span>
        <span class="n">os</span><span class="o">.</span><span class="n">chdir</span><span class="p">(</span><span class="n">cwd</span><span class="p">)</span>


<span class="k">class</span> <span class="nc">NimporterException</span><span class="p">(</span><span class="ne">Exception</span><span class="p">):</span>
    <span class="s2">&quot;Catch-all for Nimporter exceptions&quot;</span>


<span class="k">class</span> <span class="nc">NimCompileException</span><span class="p">(</span><span class="n">NimporterException</span><span class="p">):</span>
    <span class="sd">&quot;&quot;&quot;</span>
<span class="sd">    Indicates that the invocation of the Nim compiler has failed.</span>
<span class="sd">    Displays the line of code that caused the error as well as the error message</span>
<span class="sd">    returned from Nim as a Python Exception.</span>

<span class="sd">    NOTE: The provided message must contain the string: &#39;Error:&#39;</span>
<span class="sd">    &quot;&quot;&quot;</span>
    <span class="k">def</span> <span class="fm">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">msg</span><span class="p">):</span>
        <span class="k">if</span> <span class="n">sys</span><span class="o">.</span><span class="n">platform</span> <span class="o">==</span> <span class="s1">&#39;win32&#39;</span> <span class="ow">and</span> <span class="s1">&#39;external&#39;</span> <span class="ow">in</span> <span class="n">msg</span><span class="p">:</span>
            <span class="bp">self</span><span class="o">.</span><span class="n">message</span> <span class="o">=</span> <span class="n">msg</span>

        <span class="k">else</span><span class="p">:</span>
            <span class="n">nim_module</span><span class="p">,</span> <span class="n">error_msg</span> <span class="o">=</span> <span class="n">msg</span><span class="o">.</span><span class="n">split</span><span class="p">(</span><span class="s1">&#39;Error:&#39;</span><span class="p">)</span>
            <span class="n">nim_module</span> <span class="o">=</span> <span class="n">nim_module</span><span class="o">.</span><span class="n">splitlines</span><span class="p">()[</span><span class="o">-</span><span class="mi">1</span><span class="p">]</span>
            <span class="n">mod</span><span class="p">,</span> <span class="p">(</span><span class="n">line_col</span><span class="p">)</span> <span class="o">=</span> <span class="n">nim_module</span><span class="o">.</span><span class="n">split</span><span class="p">(</span><span class="s1">&#39;(&#39;</span><span class="p">)</span>
            <span class="n">nim_module</span> <span class="o">=</span> <span class="n">Path</span><span class="p">(</span><span class="n">mod</span><span class="p">)</span>
            <span class="n">line</span><span class="p">,</span> <span class="n">col</span> <span class="o">=</span> <span class="n">line_col</span><span class="o">.</span><span class="n">split</span><span class="p">(</span><span class="s1">&#39;,&#39;</span><span class="p">)</span>
            <span class="n">line</span> <span class="o">=</span> <span class="nb">int</span><span class="p">(</span><span class="n">line</span><span class="p">)</span>
            <span class="n">col</span> <span class="o">=</span> <span class="nb">int</span><span class="p">(</span><span class="n">col</span><span class="o">.</span><span class="n">replace</span><span class="p">(</span><span class="s1">&#39;)&#39;</span><span class="p">,</span> <span class="s1">&#39;&#39;</span><span class="p">))</span>
            <span class="n">message</span> <span class="o">=</span> <span class="n">error_msg</span> <span class="o">+</span> <span class="s1">&#39;</span><span class="se">\n</span><span class="s1">&#39;</span>
            
            <span class="k">with</span> <span class="nb">open</span><span class="p">(</span><span class="n">nim_module</span><span class="p">,</span> <span class="s1">&#39;r&#39;</span><span class="p">)</span> <span class="k">as</span> <span class="n">mod</span><span class="p">:</span>
                <span class="n">line</span> <span class="o">=</span> <span class="mi">0</span>
                <span class="k">for</span> <span class="n">each_line</span> <span class="ow">in</span> <span class="n">mod</span><span class="p">:</span>
                    <span class="n">line</span> <span class="o">+=</span> <span class="mi">1</span>

                    <span class="k">if</span> <span class="n">line</span> <span class="o">==</span> <span class="n">line</span><span class="p">:</span>
                        <span class="n">message</span> <span class="o">+=</span> <span class="sa">f</span><span class="s1">&#39; -&gt; </span><span class="si">{each_line}</span><span class="s1">&#39;</span>
                        
                    <span class="k">elif</span> <span class="n">line</span> <span class="o">&gt;</span> <span class="n">line</span> <span class="o">+</span> <span class="mi">2</span><span class="p">:</span>
                        <span class="k">break</span>
                    
                    <span class="k">elif</span> <span class="n">line</span> <span class="o">&gt;</span> <span class="n">line</span> <span class="o">-</span> <span class="mi">3</span><span class="p">:</span>
                        <span class="n">message</span> <span class="o">+=</span> <span class="sa">f</span><span class="s1">&#39; |  </span><span class="si">{each_line}</span><span class="s1">&#39;</span>

            <span class="bp">self</span><span class="o">.</span><span class="n">message</span> <span class="o">=</span> <span class="n">message</span><span class="o">.</span><span class="n">rstrip</span><span class="p">()</span> <span class="o">+</span> <span class="p">(</span>
                <span class="sa">f</span><span class="s1">&#39;</span><span class="se">\n\n</span><span class="s1">At {nim_module.absolute()} &#39;</span>
                <span class="sa">f</span><span class="s1">&#39;</span><span class="si">{line}</span><span class="s1">:</span><span class="si">{col}</span><span class="s1">&#39;</span>
            <span class="p">)</span>
        
    <span class="k">def</span> <span class="fm">__str__</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
        <span class="s2">&quot;Return the string representation of the given compiler error.&quot;</span>
        <span class="k">return</span> <span class="bp">self</span><span class="o">.</span><span class="n">message</span>


<span class="k">class</span> <span class="nc">NimInvokeException</span><span class="p">(</span><span class="n">NimporterException</span><span class="p">):</span>
    <span class="s2">&quot;Exception for when a given CLI command fails.&quot;</span>

    <span class="k">def</span> <span class="fm">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">cwd</span><span class="p">,</span> <span class="n">cmd_line</span><span class="p">,</span> <span class="n">errors</span><span class="p">,</span> <span class="n">out</span><span class="o">=</span><span class="s1">&#39;&#39;</span><span class="p">):</span>
        <span class="bp">self</span><span class="o">.</span><span class="n">cwd</span> <span class="o">=</span> <span class="n">Path</span><span class="p">(</span><span class="n">cwd</span><span class="p">)</span><span class="o">.</span><span class="n">resolve</span><span class="p">()</span>
        <span class="bp">self</span><span class="o">.</span><span class="n">cmd_line</span> <span class="o">=</span> <span class="n">cmd_line</span>
        <span class="bp">self</span><span class="o">.</span><span class="n">errors</span> <span class="o">=</span> <span class="n">errors</span>
        <span class="bp">self</span><span class="o">.</span><span class="n">out</span> <span class="o">=</span> <span class="n">out</span>

    <span class="k">def</span> <span class="nf">get_output</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
        <span class="s2">&quot;Return the output (if any) of the CLI command that caused the error.&quot;</span>
        <span class="k">return</span> <span class="bp">self</span><span class="o">.</span><span class="n">out</span>

    <span class="k">def</span> <span class="fm">__str__</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
        <span class="s2">&quot;Return the string representation of the error.&quot;</span>
        <span class="n">cmd</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">cmd_line</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span>
        <span class="n">message</span> <span class="o">=</span> <span class="sa">f</span><span class="s1">&#39;Failed to run command: </span><span class="si">{cmd}</span><span class="se">\n\n</span><span class="s1">&#39;</span>
        <span class="n">message</span> <span class="o">+=</span> <span class="sa">f</span><span class="s1">&#39;Current Directory:</span><span class="se">\n</span><span class="s1">    </span><span class="si">{self.cwd}</span><span class="se">\n\n</span><span class="s1">&#39;</span>
        <span class="n">message</span> <span class="o">+=</span> <span class="sa">f</span><span class="s1">&#39;Error Message:</span><span class="se">\n</span><span class="s1">&#39;</span>
        <span class="n">message</span> <span class="o">+=</span> <span class="s1">&#39;</span><span class="se">\n</span><span class="s1">    &#39;</span><span class="o">.</span><span class="n">join</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">errors</span><span class="p">)</span> <span class="o">+</span> <span class="s1">&#39;</span><span class="se">\n\n</span><span class="s1">&#39;</span>
        <span class="n">message</span> <span class="o">+=</span> <span class="sa">f</span><span class="s1">&#39;Command Line Arguments:</span><span class="se">\n</span><span class="s1">    </span><span class="si">{cmd}</span><span class="se">\n</span><span class="s1">&#39;</span>
        <span class="k">for</span> <span class="n">arg</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">cmd_line</span><span class="p">[</span><span class="mi">1</span><span class="p">:]:</span>
            <span class="n">message</span> <span class="o">+=</span> <span class="sa">f</span><span class="s1">&#39;        </span><span class="si">{arg}</span><span class="se">\n</span><span class="s1">&#39;</span>
        <span class="k">return</span> <span class="n">message</span>


<span class="k">class</span> <span class="nc">NimCompiler</span><span class="p">:</span>
    <span class="sd">&quot;&quot;&quot;</span>
<span class="sd">    Nim compiler invoker. Features:</span>
<span class="sd">     - Compile Nim files and return any failure messages as Python exceptions.</span>
<span class="sd">     - Store hashes of Nim source files to only recompile when module changes.</span>
<span class="sd">     - Stores hash in __pycache__ directory to not clutter up file system.</span>
<span class="sd">     - Compile Nim files to C and bundle them as an Extension for distribution.</span>
<span class="sd">    </span>
<span class="sd">    Attributes:</span>
<span class="sd">        EXT(str): the extension to use for the importable build artifact.</span>
<span class="sd">        NIM_CLI_ARGS(list): compiler switches common to all builds.</span>
<span class="sd">    &quot;&quot;&quot;</span>
    <span class="n">EXT</span> <span class="o">=</span> <span class="s1">&#39;.pyd&#39;</span> <span class="k">if</span> <span class="n">sys</span><span class="o">.</span><span class="n">platform</span> <span class="o">==</span> <span class="s1">&#39;win32&#39;</span> <span class="k">else</span> <span class="s1">&#39;.so&#39;</span>
    <span class="n">NIM_CLI_ARGS</span> <span class="o">=</span> <span class="p">[</span>
        <span class="s1">&#39;--opt:speed&#39;</span><span class="p">,</span>
        <span class="s1">&#39;--parallelBuild:0&#39;</span><span class="p">,</span>
        <span class="s1">&#39;--gc:markAndSweep&#39;</span><span class="p">,</span>
        <span class="s1">&#39;--threads:on&#39;</span><span class="p">,</span>
        <span class="s1">&#39;--app:lib&#39;</span><span class="p">,</span>
        <span class="s1">&#39;-d:release&#39;</span><span class="p">,</span>
        <span class="s1">&#39;-d:ssl&#39;</span>
    <span class="p">]</span> <span class="o">+</span> <span class="p">([</span><span class="s1">&#39;--cc:vcc&#39;</span><span class="p">]</span> <span class="k">if</span> <span class="n">sys</span><span class="o">.</span><span class="n">platform</span> <span class="o">==</span> <span class="s1">&#39;win32&#39;</span> <span class="k">else</span> <span class="p">[])</span>
    <span class="n">EXT_DIR</span> <span class="o">=</span> <span class="s1">&#39;nim-extensions&#39;</span>

    <span class="nd">@classmethod</span>
    <span class="k">def</span> <span class="nf">build_artifact</span><span class="p">(</span><span class="bp">cls</span><span class="p">,</span> <span class="n">module_path</span><span class="p">):</span>
        <span class="sd">&quot;&quot;&quot;</span>
<span class="sd">        Returns the Path to the built .PYD or .SO. Does not imply it has already</span>
<span class="sd">        been built.</span>

<span class="sd">        Args:</span>
<span class="sd">            module_path(Path): the path to the module or library.</span>

<span class="sd">        Returns:</span>
<span class="sd">            The path to a build artifact if compilation were to succeed. If the</span>
<span class="sd">            module_path is a directory, an appropriate build artifact path</span>
<span class="sd">            within that directory is returned.</span>
<span class="sd">        &quot;&quot;&quot;</span>
        <span class="n">filename</span> <span class="o">=</span> <span class="n">module_path</span><span class="o">.</span><span class="n">stem</span> <span class="o">+</span> <span class="bp">cls</span><span class="o">.</span><span class="n">EXT</span>
        <span class="k">return</span> <span class="p">(</span><span class="bp">cls</span><span class="o">.</span><span class="n">pycache_dir</span><span class="p">(</span><span class="n">module_path</span><span class="p">)</span> <span class="o">/</span> <span class="n">filename</span><span class="p">)</span><span class="o">.</span><span class="n">resolve</span><span class="p">()</span>

    <span class="nd">@classmethod</span>
    <span class="k">def</span> <span class="nf">pycache_dir</span><span class="p">(</span><span class="bp">cls</span><span class="p">,</span> <span class="n">module_path</span><span class="p">):</span>
        <span class="sd">&quot;&quot;&quot;</span>
<span class="sd">        Return the `__pycache__` directory as a Path.</span>

<span class="sd">        Works the same as Python&#39;s `__pycache__` directory except now it works</span>
<span class="sd">        with Nim extensions also. It works literally exactly like Python.</span>

<span class="sd">        Args:</span>
<span class="sd">            module_path(Path): the path to a given Nim module or library.</span>

<span class="sd">        Returns:</span>
<span class="sd">            The Path to the `__pycache__` directory that the build artifact</span>
<span class="sd">            should be stored.</span>
<span class="sd">        &quot;&quot;&quot;</span>
        <span class="k">if</span> <span class="n">module_path</span><span class="o">.</span><span class="n">is_dir</span><span class="p">():</span>
            <span class="k">return</span> <span class="p">(</span><span class="n">module_path</span> <span class="o">/</span> <span class="s1">&#39;__pycache__&#39;</span><span class="p">)</span><span class="o">.</span><span class="n">resolve</span><span class="p">()</span>
        <span class="k">else</span><span class="p">:</span>
            <span class="k">return</span> <span class="p">(</span><span class="n">module_path</span><span class="o">.</span><span class="n">parent</span> <span class="o">/</span> <span class="s1">&#39;__pycache__&#39;</span><span class="p">)</span><span class="o">.</span><span class="n">resolve</span><span class="p">()</span>

    <span class="nd">@classmethod</span>
    <span class="k">def</span> <span class="nf">invoke_compiler</span><span class="p">(</span><span class="bp">cls</span><span class="p">,</span> <span class="n">nim_args</span><span class="p">:</span> <span class="nb">list</span><span class="p">):</span>
        <span class="sd">&quot;&quot;&quot;</span>
<span class="sd">        Invokes the compiler (or any executable) and returns the output.</span>

<span class="sd">        While this can (and has been) used to call executables other than Nim</span>
<span class="sd">        and Nimble, it should be noted that the warnings and hints are artifacts</span>
<span class="sd">        of being mainly targeted as a Nim compiler invoker.</span>

<span class="sd">        Args:</span>
<span class="sd">            nim_args(list): the arg being the executable and the rest are args.</span>

<span class="sd">        Returns:</span>
<span class="sd">            A tuple containing any errors, warnings, or hints from the</span>
<span class="sd">            compilation process.</span>
<span class="sd">        &quot;&quot;&quot;</span>
        <span class="n">process</span> <span class="o">=</span> <span class="n">subprocess</span><span class="o">.</span><span class="n">run</span><span class="p">(</span>
            <span class="n">nim_args</span><span class="p">,</span> <span class="n">stdout</span><span class="o">=</span><span class="n">subprocess</span><span class="o">.</span><span class="n">PIPE</span><span class="p">,</span> <span class="n">stderr</span><span class="o">=</span><span class="n">subprocess</span><span class="o">.</span><span class="n">PIPE</span>
        <span class="p">)</span>
        <span class="n">out</span><span class="p">,</span> <span class="n">err</span> <span class="o">=</span> <span class="n">process</span><span class="o">.</span><span class="n">stdout</span><span class="p">,</span> <span class="n">process</span><span class="o">.</span><span class="n">stderr</span>
        <span class="n">out</span> <span class="o">=</span> <span class="n">out</span><span class="o">.</span><span class="n">decode</span><span class="p">()</span> <span class="k">if</span> <span class="n">out</span> <span class="k">else</span> <span class="s1">&#39;&#39;</span>
        <span class="n">err</span> <span class="o">=</span> <span class="n">err</span><span class="o">.</span><span class="n">decode</span><span class="p">()</span> <span class="k">if</span> <span class="n">err</span> <span class="k">else</span> <span class="s1">&#39;&#39;</span>
        <span class="n">lines</span> <span class="o">=</span> <span class="p">(</span><span class="n">out</span> <span class="o">+</span> <span class="n">err</span><span class="p">)</span><span class="o">.</span><span class="n">splitlines</span><span class="p">()</span>

        <span class="n">errors</span>   <span class="o">=</span> <span class="p">[</span><span class="n">line</span> <span class="k">for</span> <span class="n">line</span> <span class="ow">in</span> <span class="n">lines</span> <span class="k">if</span> <span class="s1">&#39;Error:&#39;</span> <span class="ow">in</span> <span class="n">line</span><span class="p">]</span>
        <span class="n">warnings</span> <span class="o">=</span> <span class="p">[</span><span class="n">line</span> <span class="k">for</span> <span class="n">line</span> <span class="ow">in</span> <span class="n">lines</span> <span class="k">if</span> <span class="s1">&#39;Warning:&#39;</span> <span class="ow">in</span> <span class="n">line</span><span class="p">]</span>
        <span class="n">hints</span>    <span class="o">=</span> <span class="p">[</span><span class="n">line</span> <span class="k">for</span> <span class="n">line</span> <span class="ow">in</span> <span class="n">lines</span> <span class="k">if</span> <span class="s1">&#39;Hint:&#39;</span> <span class="ow">in</span> <span class="n">line</span><span class="p">]</span>

        <span class="k">return</span> <span class="n">out</span><span class="p">,</span> <span class="n">errors</span><span class="p">,</span> <span class="n">warnings</span><span class="p">,</span> <span class="n">hints</span>

    <span class="nd">@classmethod</span>
    <span class="k">def</span> <span class="nf">ensure_nimpy</span><span class="p">(</span><span class="bp">cls</span><span class="p">):</span>
        <span class="sd">&quot;&quot;&quot;</span>
<span class="sd">        Makes sure that the Nimpy Nim library is installed.</span>

<span class="sd">        Verifies that the [Nimpy Library](https://github.com/yglukhov/nimpy) is</span>
<span class="sd">        installed and installs it otherwise.</span>

<span class="sd">        NOTE: Nimporter would not be possible without Nimpy. Thank you</span>
<span class="sd">        Yuriy Glukhov for making this project possible!</span>
<span class="sd">        &quot;&quot;&quot;</span>
        <span class="n">out</span><span class="p">,</span> <span class="n">errors</span><span class="p">,</span> <span class="n">_</span><span class="p">,</span> <span class="n">_</span> <span class="o">=</span> <span class="bp">cls</span><span class="o">.</span><span class="n">invoke_compiler</span><span class="p">(</span><span class="s1">&#39;nimble path nimpy&#39;</span><span class="o">.</span><span class="n">split</span><span class="p">())</span>

        <span class="k">if</span> <span class="ow">not</span> <span class="n">out</span> <span class="ow">or</span> <span class="n">errors</span><span class="p">:</span>
            <span class="n">nimble_args</span> <span class="o">=</span> <span class="s1">&#39;nimble install nimpy --accept&#39;</span><span class="o">.</span><span class="n">split</span><span class="p">()</span>
            <span class="n">out</span><span class="p">,</span> <span class="n">errors</span><span class="p">,</span> <span class="n">_</span><span class="p">,</span> <span class="n">_</span> <span class="o">=</span> <span class="bp">cls</span><span class="o">.</span><span class="n">invoke_compiler</span><span class="p">(</span><span class="n">nimble_args</span><span class="p">)</span>

        <span class="k">if</span> <span class="n">errors</span><span class="p">:</span> <span class="k">raise</span> <span class="n">NimInvokeException</span><span class="p">(</span><span class="n">Path</span><span class="p">(),</span> <span class="n">nimble_args</span><span class="p">,</span> <span class="n">errors</span><span class="p">,</span> <span class="n">out</span><span class="p">)</span>

    <span class="nd">@staticmethod</span>
    <span class="k">def</span> <span class="nf">get_import_prefix</span><span class="p">(</span><span class="n">module_path</span><span class="p">,</span> <span class="n">root</span><span class="p">):</span>
        <span class="sd">&quot;&quot;&quot;</span>
<span class="sd">        Computes the proper name of a Nim module amid a given Python project.</span>

<span class="sd">        This method is needed because Nim Extensions do not automatically know</span>
<span class="sd">        where they are within a given Python namespace. This method is vital for</span>
<span class="sd">        recursing through an entire Python project to find every Nim Extension</span>
<span class="sd">        module and library while preserving the namespace containing each one.</span>

<span class="sd">        Args:</span>
<span class="sd">            module_path(Path): the module for which to determine its namespace.</span>
<span class="sd">            root(Path): the path to the Python project containing the Extension.</span>

<span class="sd">        Returns:</span>
<span class="sd">            A tuple of packages containing the given module.</span>
<span class="sd">        &quot;&quot;&quot;</span>
        <span class="n">root_path</span> <span class="o">=</span> <span class="n">root</span><span class="o">.</span><span class="n">resolve</span><span class="p">()</span>
        <span class="n">full_path</span> <span class="o">=</span> <span class="n">module_path</span><span class="o">.</span><span class="n">resolve</span><span class="p">()</span>

        <span class="k">assert</span> <span class="n">full_path</span> <span class="o">&gt;=</span> <span class="n">root_path</span><span class="p">,</span> <span class="s1">&#39;Extension path is not within root dir.&#39;</span>

        <span class="k">return</span> <span class="n">full_path</span><span class="o">.</span><span class="n">parts</span><span class="p">[</span><span class="nb">len</span><span class="p">(</span><span class="n">root_path</span><span class="o">.</span><span class="n">parts</span><span class="p">):]</span>

    <span class="nd">@classmethod</span>
    <span class="k">def</span> <span class="nf">find_nim_std_lib</span><span class="p">(</span><span class="bp">cls</span><span class="p">):</span>
        <span class="sd">&quot;&quot;&quot;</span>
<span class="sd">        Finds the path to the `lib/` directory within a given Nim installation.</span>

<span class="sd">        Has the ability to find Nim&#39;s stdlib on Windows, MacOS, and Linux. Can</span>
<span class="sd">        also find the stdlib when Nim was installed via Choosenim. Additionally,</span>
<span class="sd">        it can even find the stdlib of the currently selected toolchain when</span>
<span class="sd">        using Choosenim.</span>

<span class="sd">        Returns:</span>
<span class="sd">            The Path to the Nim stdlib &#39;lib&#39; directory if it exists and None</span>
<span class="sd">            otherwise.</span>
<span class="sd">        &quot;&quot;&quot;</span>

        <span class="c1"># Installed via ChooseNim</span>
        <span class="k">if</span> <span class="n">shutil</span><span class="o">.</span><span class="n">which</span><span class="p">(</span><span class="s1">&#39;choosenim&#39;</span><span class="p">):</span>
            <span class="n">o</span><span class="p">,</span> <span class="n">_</span><span class="p">,</span> <span class="n">_</span><span class="p">,</span> <span class="n">_</span> <span class="o">=</span> <span class="bp">cls</span><span class="o">.</span><span class="n">invoke_compiler</span><span class="p">(</span>
                <span class="s1">&#39;choosenim show -y --nocolor&#39;</span><span class="o">.</span><span class="n">split</span><span class="p">()</span>
            <span class="p">)</span>
            <span class="p">(</span><span class="n">choosenim</span><span class="p">,)</span> <span class="o">=</span> <span class="p">[</span><span class="n">i</span> <span class="k">for</span> <span class="n">i</span> <span class="ow">in</span> <span class="n">o</span><span class="o">.</span><span class="n">splitlines</span><span class="p">()</span> <span class="k">if</span> <span class="s1">&#39;Path:&#39;</span> <span class="ow">in</span> <span class="n">i</span><span class="p">]</span>
            <span class="n">toolchain</span> <span class="o">=</span> <span class="n">Path</span><span class="p">(</span><span class="n">choosenim</span><span class="o">.</span><span class="n">split</span><span class="p">(</span><span class="s1">&#39;Path:&#39;</span><span class="p">)</span><span class="o">.</span><span class="n">pop</span><span class="p">()</span><span class="o">.</span><span class="n">strip</span><span class="p">())</span>
            <span class="n">stdlib</span> <span class="o">=</span> <span class="n">toolchain</span> <span class="o">/</span> <span class="s1">&#39;lib&#39;</span>
            <span class="k">if</span> <span class="ow">not</span> <span class="p">(</span><span class="n">stdlib</span> <span class="o">/</span> <span class="s1">&#39;system.nim&#39;</span><span class="p">)</span><span class="o">.</span><span class="n">exists</span><span class="p">():</span>
                <span class="k">return</span> <span class="kc">None</span>
            <span class="k">return</span> <span class="n">stdlib</span><span class="o">.</span><span class="n">resolve</span><span class="p">()</span><span class="o">.</span><span class="n">absolute</span><span class="p">()</span>

        <span class="c1"># Installed manually</span>
        <span class="n">nimexe</span> <span class="o">=</span> <span class="n">shutil</span><span class="o">.</span><span class="n">which</span><span class="p">(</span><span class="s1">&#39;nim&#39;</span><span class="p">)</span>
        <span class="k">if</span> <span class="ow">not</span> <span class="n">nimexe</span><span class="p">:</span>
            <span class="k">return</span> <span class="kc">None</span>
        <span class="n">nimexe</span> <span class="o">=</span> <span class="n">Path</span><span class="p">(</span><span class="n">nimexe</span><span class="p">)</span>
        <span class="n">result</span> <span class="o">=</span> <span class="n">nimexe</span><span class="o">.</span><span class="n">parent</span> <span class="o">/</span> <span class="s1">&#39;../lib&#39;</span>
        <span class="k">if</span> <span class="ow">not</span> <span class="p">(</span><span class="n">result</span> <span class="o">/</span> <span class="s1">&#39;system.nim&#39;</span><span class="p">)</span><span class="o">.</span><span class="n">exists</span><span class="p">():</span>
            <span class="n">result</span> <span class="o">=</span> <span class="n">nimexe</span><span class="o">.</span><span class="n">resolve</span><span class="p">()</span><span class="o">.</span><span class="n">parent</span> <span class="o">/</span> <span class="s1">&#39;../lib&#39;</span>
            <span class="k">if</span> <span class="ow">not</span> <span class="p">(</span><span class="n">result</span> <span class="o">/</span> <span class="s1">&#39;system.nim&#39;</span><span class="p">)</span><span class="o">.</span><span class="n">exists</span><span class="p">():</span>
                <span class="k">return</span> <span class="kc">None</span>
        <span class="k">return</span> <span class="n">result</span><span class="o">.</span><span class="n">resolve</span><span class="p">()</span><span class="o">.</span><span class="n">absolute</span><span class="p">()</span>

    <span class="nd">@classmethod</span>
    <span class="k">def</span> <span class="nf">get_switches</span><span class="p">(</span><span class="bp">cls</span><span class="p">,</span> <span class="n">switch_file</span><span class="p">,</span> <span class="o">**</span><span class="n">global_scope</span><span class="p">):</span>
        <span class="sd">&quot;&quot;&quot;</span>
<span class="sd">        Convenience function to return the switches from a given switchfile.</span>

<span class="sd">        Works by exposing a global scope to the switch file and then evaluating</span>
<span class="sd">        it. The resulting variable: `__switches__` should have been defined</span>
<span class="sd">        within the script which should contain the keys: &quot;import&quot; and &quot;bundle&quot;.</span>

<span class="sd">        The &quot;import&quot; key should be a list of CLI args that should be passed to</span>
<span class="sd">        the Nim compiler when importing the given Nim library.</span>

<span class="sd">        The &quot;bundle&quot; key should be a list of CLI args that should be passed to</span>
<span class="sd">        the Nim compiler when creating an Extension object from the C sources.</span>

<span class="sd">        When evaluated, the switchfile can make use of a few global variables</span>
<span class="sd">        that allow it to make certain decisions regarding the outcome of the</span>
<span class="sd">        compilation:</span>

<span class="sd">         * **MODULE_PATH**: the path to the actual Nim source file to compile</span>
<span class="sd">         * **BUILD_ARTIFACT**: can be used when building a module</span>
<span class="sd">         * **BUILD_DIR**: can be used when building a library</span>
<span class="sd">         * **IS_LIBRARY**: used to determine if a library/module is being built.</span>

<span class="sd">        The reason for the switchfile being a Python script is that different</span>
<span class="sd">        platforms will require different compilation switches. The switchfile</span>
<span class="sd">        author can make use of `sys.platform` to query platform information.</span>

<span class="sd">        Returns:</span>
<span class="sd">            A dictionary containing the keys: &quot;import&quot; and &quot;bundle&quot;, signifying</span>
<span class="sd">            the CLI arguments used when importing and building an extension</span>
<span class="sd">            module respectively.</span>
<span class="sd">        &quot;&quot;&quot;</span>
        <span class="n">global_scope</span> <span class="o">=</span> <span class="n">global_scope</span><span class="o">.</span><span class="n">copy</span><span class="p">()</span>
        <span class="k">assert</span> <span class="n">switch_file</span><span class="o">.</span><span class="n">exists</span><span class="p">(),</span> <span class="p">(</span>
            <span class="s1">&#39;Cannot open nonexistent switch file: &#39;</span> <span class="o">+</span> <span class="nb">str</span><span class="p">(</span><span class="n">switch_file</span><span class="p">)</span>
        <span class="p">)</span>
        <span class="n">exec</span><span class="p">(</span><span class="n">switch_file</span><span class="o">.</span><span class="n">read_text</span><span class="p">(),</span> <span class="n">global_scope</span><span class="p">)</span>
        <span class="k">return</span> <span class="n">global_scope</span><span class="p">[</span><span class="s1">&#39;__switches__&#39;</span><span class="p">]</span>

    <span class="nd">@classmethod</span>
    <span class="k">def</span> <span class="nf">compile_nim_extension</span><span class="p">(</span><span class="bp">cls</span><span class="p">,</span> <span class="n">module_path</span><span class="p">,</span> <span class="n">root</span><span class="p">,</span> <span class="o">*</span><span class="p">,</span> <span class="n">library</span><span class="p">:</span> <span class="nb">bool</span><span class="p">):</span>
        <span class="sd">&quot;&quot;&quot;</span>
<span class="sd">        Compiles/returns an Extension and installs `.nimble` dependencies.</span>

<span class="sd">        Libraries MUST have a Nim file named &quot;&lt;library name&gt;.nim&quot; at the project</span>
<span class="sd">        root as well as a file ending with &quot;.nimble&quot;.</span>

<span class="sd">        NOTE: The library parameter signifies (albeit subtly) that the given Nim</span>
<span class="sd">        library has (can have) dependencies specified in a Nimble file.</span>

<span class="sd">        Args:</span>
<span class="sd">            module_path(Path): the path to the library directory or a Nim file.</span>
<span class="sd">            root(Path): the path to the directory containing the entire project.</span>
<span class="sd">            library(bool): hint as to how to treat the `module_path` parameter.</span>

<span class="sd">        Returns:</span>
<span class="sd">            An Extension upon successful compilation, else None.</span>

<span class="sd">        Raises:</span>
<span class="sd">            Exception if the library path does not contain the files listed</span>
<span class="sd">            above or any other compilation error.</span>
<span class="sd">        &quot;&quot;&quot;</span>

        <span class="k">if</span> <span class="ow">not</span> <span class="n">module_path</span><span class="o">.</span><span class="n">exists</span><span class="p">():</span>
            <span class="k">raise</span> <span class="n">NimporterException</span><span class="p">(</span>
                <span class="sa">f</span><span class="s1">&#39;{module_path.absolute()} does not exist.&#39;</span>
            <span class="p">)</span>

        <span class="n">module_name</span> <span class="o">=</span> <span class="n">module_path</span><span class="o">.</span><span class="n">stem</span>

        <span class="k">if</span> <span class="n">module_path</span><span class="o">.</span><span class="n">is_file</span><span class="p">():</span>
            <span class="n">library_path</span> <span class="o">=</span> <span class="n">module_path</span><span class="o">.</span><span class="n">parent</span><span class="o">.</span><span class="n">resolve</span><span class="p">()</span>
            
        <span class="k">elif</span> <span class="n">module_path</span><span class="o">.</span><span class="n">is_dir</span><span class="p">():</span>
            <span class="n">library_path</span> <span class="o">=</span> <span class="n">module_path</span><span class="o">.</span><span class="n">resolve</span><span class="p">()</span>
            <span class="n">module_path</span> <span class="o">=</span> <span class="n">library_path</span> <span class="o">/</span> <span class="p">(</span><span class="n">library_path</span><span class="o">.</span><span class="n">name</span> <span class="o">+</span> <span class="s1">&#39;.nim&#39;</span><span class="p">)</span>

        <span class="k">if</span> <span class="n">library</span> <span class="ow">and</span> <span class="ow">not</span> <span class="nb">any</span><span class="p">(</span><span class="n">library_path</span><span class="o">.</span><span class="n">glob</span><span class="p">(</span><span class="s1">&#39;*.nimble&#39;</span><span class="p">)):</span>
            <span class="k">raise</span> <span class="n">NimporterException</span><span class="p">(</span>
            <span class="sa">f</span><span class="s2">&quot;Library: </span><span class="si">{library_path}</span><span class="s2"> doesn&#39;t contain a .nimble file&quot;</span>
        <span class="p">)</span>

        <span class="bp">cls</span><span class="o">.</span><span class="n">ensure_nimpy</span><span class="p">()</span>

        <span class="c1"># Coerce proper import path using root path</span>
        <span class="n">import_prefix</span> <span class="o">=</span> <span class="bp">cls</span><span class="o">.</span><span class="n">get_import_prefix</span><span class="p">(</span><span class="n">module_path</span><span class="o">.</span><span class="n">parent</span><span class="p">,</span> <span class="n">root</span><span class="p">)</span>
        <span class="n">module_part</span> <span class="o">=</span> <span class="nb">tuple</span><span class="p">()</span> <span class="k">if</span> <span class="n">library</span> <span class="k">else</span> <span class="p">(</span><span class="n">module_name</span><span class="p">,)</span>
        <span class="n">import_path</span> <span class="o">=</span> <span class="s1">&#39;.&#39;</span><span class="o">.</span><span class="n">join</span><span class="p">(</span><span class="n">import_prefix</span> <span class="o">+</span> <span class="n">module_part</span><span class="p">)</span>

        <span class="c1"># Record results of build so it can be copied into source archive</span>
        <span class="n">extension_dir</span> <span class="o">=</span> <span class="n">root</span> <span class="o">/</span> <span class="bp">cls</span><span class="o">.</span><span class="n">EXT_DIR</span>
        <span class="n">extension_dir</span><span class="o">.</span><span class="n">mkdir</span><span class="p">(</span><span class="n">parents</span><span class="o">=</span><span class="kc">True</span><span class="p">,</span> <span class="n">exist_ok</span><span class="o">=</span><span class="kc">True</span><span class="p">)</span>
        <span class="n">build_dir</span> <span class="o">=</span> <span class="n">extension_dir</span><span class="o">.</span><span class="n">absolute</span><span class="p">()</span> <span class="o">/</span> <span class="n">import_path</span>
        <span class="n">build_dir</span><span class="o">.</span><span class="n">mkdir</span><span class="p">(</span><span class="n">exist_ok</span><span class="o">=</span><span class="kc">True</span><span class="p">)</span>
        <span class="n">build_dir_relative</span> <span class="o">=</span> <span class="n">extension_dir</span> <span class="o">/</span> <span class="n">import_path</span>

        <span class="c1"># Switches file found</span>
        <span class="n">switch_file</span> <span class="o">=</span> <span class="n">library_path</span> <span class="o">/</span> <span class="s1">&#39;switches.py&#39;</span>
        <span class="k">if</span> <span class="n">switch_file</span><span class="o">.</span><span class="n">exists</span><span class="p">():</span>
            <span class="n">switches</span> <span class="o">=</span> <span class="bp">cls</span><span class="o">.</span><span class="n">get_switches</span><span class="p">(</span>
                <span class="n">switch_file</span><span class="p">,</span>
                <span class="n">MODULE_PATH</span><span class="o">=</span><span class="n">module_path</span><span class="p">,</span>
                <span class="n">BUILD_DIR</span><span class="o">=</span><span class="n">build_dir</span><span class="p">,</span>
                <span class="c1"># Necessary for import/bundle compatibility</span>
                <span class="n">BUILD_ARTIFACT</span><span class="o">=</span><span class="kc">None</span><span class="p">,</span>
                <span class="n">IS_LIBRARY</span><span class="o">=</span><span class="n">library</span>
            <span class="p">)</span>
            <span class="n">nim_args</span> <span class="o">=</span> <span class="n">switches</span><span class="p">[</span><span class="s1">&#39;bundle&#39;</span><span class="p">]</span>

        <span class="c1"># Use standard switches</span>
        <span class="k">else</span><span class="p">:</span>
            <span class="n">exe</span> <span class="o">=</span> <span class="p">[</span><span class="s1">&#39;nimble&#39;</span> <span class="k">if</span> <span class="n">library</span> <span class="k">else</span> <span class="s1">&#39;nim&#39;</span><span class="p">,</span> <span class="s1">&#39;cc&#39;</span><span class="p">,</span> <span class="s1">&#39;-c&#39;</span><span class="p">]</span>
            <span class="n">nim_args</span> <span class="o">=</span> <span class="p">(</span>
                <span class="n">exe</span> <span class="o">+</span> <span class="bp">cls</span><span class="o">.</span><span class="n">NIM_CLI_ARGS</span> <span class="o">+</span>
                <span class="p">[</span><span class="sa">f</span><span class="s1">&#39;--nimcache:</span><span class="si">{build_dir}</span><span class="s1">&#39;</span><span class="p">,</span> <span class="sa">f</span><span class="s1">&#39;</span><span class="si">{module_path}</span><span class="s1">&#39;</span><span class="p">]</span> <span class="o">+</span>
                <span class="p">([</span><span class="s1">&#39;--accept&#39;</span><span class="p">]</span> <span class="k">if</span> <span class="n">library</span> <span class="k">else</span> <span class="p">[])</span>
            <span class="p">)</span>

        <span class="k">with</span> <span class="n">cd</span><span class="p">(</span><span class="n">library_path</span> <span class="k">if</span> <span class="n">library</span> <span class="k">else</span> <span class="n">Path</span><span class="p">(</span><span class="s1">&#39;.&#39;</span><span class="p">))</span> <span class="k">as</span> <span class="n">tmp_cwd</span><span class="p">:</span>
            <span class="n">output</span><span class="p">,</span> <span class="n">errors</span><span class="p">,</span> <span class="n">warnings</span><span class="p">,</span> <span class="n">hints</span> <span class="o">=</span> <span class="bp">cls</span><span class="o">.</span><span class="n">invoke_compiler</span><span class="p">(</span><span class="n">nim_args</span><span class="p">)</span>

        <span class="k">if</span> <span class="n">errors</span><span class="p">:</span>
            <span class="k">if</span> <span class="n">library</span><span class="p">:</span>
                <span class="k">raise</span> <span class="n">NimInvokeException</span><span class="p">(</span><span class="n">tmp_cwd</span><span class="p">,</span> <span class="n">nim_args</span><span class="p">,</span> <span class="n">errors</span><span class="p">,</span> <span class="n">output</span><span class="p">)</span>
            <span class="k">else</span><span class="p">:</span>
                <span class="k">raise</span> <span class="n">NimCompileException</span><span class="p">(</span><span class="n">errors</span><span class="p">[</span><span class="mi">0</span><span class="p">])</span>

        <span class="k">for</span> <span class="n">warn</span> <span class="ow">in</span> <span class="n">warnings</span><span class="p">:</span> <span class="nb">print</span><span class="p">(</span><span class="n">warn</span><span class="p">)</span>

        <span class="n">csources</span> <span class="o">=</span> <span class="p">[</span>
            <span class="nb">str</span><span class="p">(</span><span class="n">c</span><span class="p">)</span> <span class="k">for</span> <span class="n">c</span> <span class="ow">in</span> <span class="n">build_dir_relative</span><span class="o">.</span><span class="n">iterdir</span><span class="p">()</span> <span class="k">if</span> <span class="n">c</span><span class="o">.</span><span class="n">suffix</span> <span class="o">==</span> <span class="s1">&#39;.c&#39;</span>
        <span class="p">]</span>

        <span class="c1"># Copy over needed header(s)</span>
        <span class="n">NIMBASE</span> <span class="o">=</span> <span class="s1">&#39;nimbase.h&#39;</span>
        <span class="n">nimbase</span> <span class="o">=</span> <span class="bp">cls</span><span class="o">.</span><span class="n">find_nim_std_lib</span><span class="p">()</span> <span class="o">/</span> <span class="n">NIMBASE</span>
        <span class="n">nimbase_dest</span> <span class="o">=</span> <span class="nb">str</span><span class="p">(</span><span class="n">build_dir_relative</span> <span class="o">/</span> <span class="n">NIMBASE</span><span class="p">)</span>
        <span class="n">shutil</span><span class="o">.</span><span class="n">copyfile</span><span class="p">(</span><span class="nb">str</span><span class="p">(</span><span class="n">nimbase</span><span class="p">),</span> <span class="n">nimbase_dest</span><span class="p">)</span>

        <span class="c1"># Properly handle bundling headers into the source distribution</span>
        <span class="n">manifest</span> <span class="o">=</span> <span class="n">root</span> <span class="o">/</span> <span class="s1">&#39;MANIFEST.in&#39;</span>
        <span class="k">if</span> <span class="ow">not</span> <span class="n">manifest</span><span class="o">.</span><span class="n">exists</span><span class="p">():</span>
            <span class="n">manifest</span><span class="o">.</span><span class="n">write_text</span><span class="p">(</span><span class="s1">&#39;# NIMPORTER BUNDLE</span><span class="se">\n</span><span class="s1">&#39;</span><span class="p">)</span>

        <span class="k">with</span> <span class="n">manifest</span><span class="o">.</span><span class="n">open</span><span class="p">(</span><span class="s1">&#39;a&#39;</span><span class="p">)</span> <span class="k">as</span> <span class="n">file</span><span class="p">:</span>
            <span class="n">file</span><span class="o">.</span><span class="n">write</span><span class="p">(</span><span class="sa">f</span><span class="s1">&#39;include </span><span class="si">{nimbase_dest}</span><span class="se">\n</span><span class="s1">&#39;</span><span class="p">)</span>

        <span class="k">return</span> <span class="n">Extension</span><span class="p">(</span>
            <span class="n">name</span><span class="o">=</span><span class="n">import_path</span><span class="p">,</span>
            <span class="n">sources</span><span class="o">=</span><span class="n">csources</span><span class="p">,</span>
            <span class="n">include_dirs</span><span class="o">=</span><span class="p">[</span><span class="nb">str</span><span class="p">(</span><span class="n">build_dir</span><span class="p">)]</span>
        <span class="p">)</span>

    <span class="nd">@classmethod</span>
    <span class="k">def</span> <span class="nf">compile_nim_code</span><span class="p">(</span><span class="bp">cls</span><span class="p">,</span> <span class="n">module_path</span><span class="p">,</span> <span class="n">build_artifact</span><span class="p">,</span> <span class="o">*</span><span class="p">,</span> <span class="n">library</span><span class="p">:</span> <span class="nb">bool</span><span class="p">):</span>
        <span class="sd">&quot;&quot;&quot;</span>
<span class="sd">        Returns a Spec object so a Nim module/library can be directly imported.</span>

<span class="sd">        NOTE: The `module_path` keyword argument can be either a path to a Nim</span>
<span class="sd">        file (in the case of `library=False`) or a path to a directory (in the</span>
<span class="sd">        case of `library=True`). However, it has a third supported usage. It can</span>
<span class="sd">        be a Nim module when `library=True` and this method will search for the</span>
<span class="sd">        Nimble file alongside the given path.</span>

<span class="sd">        NOTE: The library parameter signifies (albeit subtly) that the given Nim</span>
<span class="sd">        library has (can have) dependencies specified in a Nimble file.</span>
<span class="sd">        &quot;&quot;&quot;</span>

        <span class="k">if</span> <span class="ow">not</span> <span class="n">module_path</span><span class="o">.</span><span class="n">exists</span><span class="p">():</span>
            <span class="k">raise</span> <span class="n">NimporterException</span><span class="p">(</span>
                <span class="sa">f</span><span class="s1">&#39;{module_path.absolute()} does not exist.&#39;</span>
            <span class="p">)</span>

        <span class="k">if</span> <span class="n">library</span> <span class="ow">and</span> <span class="n">module_path</span><span class="o">.</span><span class="n">is_file</span><span class="p">():</span>
            <span class="k">raise</span> <span class="n">NimporterException</span><span class="p">(</span>
                <span class="s1">&#39;Librarys are built using folder name, not specific Nim module&#39;</span>
            <span class="p">)</span>

        <span class="k">elif</span> <span class="ow">not</span> <span class="n">library</span> <span class="ow">and</span> <span class="n">module_path</span><span class="o">.</span><span class="n">is_dir</span><span class="p">():</span>
            <span class="k">raise</span> <span class="n">NimporterException</span><span class="p">(</span>
                <span class="s1">&#39;Modules are built using module name, not containing folder&#39;</span>
            <span class="p">)</span>

        <span class="k">if</span> <span class="n">module_path</span><span class="o">.</span><span class="n">is_file</span><span class="p">():</span>
            <span class="n">library_path</span> <span class="o">=</span> <span class="n">module_path</span><span class="o">.</span><span class="n">parent</span><span class="o">.</span><span class="n">resolve</span><span class="p">()</span>

        <span class="k">elif</span> <span class="n">module_path</span><span class="o">.</span><span class="n">is_dir</span><span class="p">():</span>
            <span class="n">library_path</span> <span class="o">=</span> <span class="n">module_path</span><span class="o">.</span><span class="n">resolve</span><span class="p">()</span>
            <span class="n">module_path</span> <span class="o">=</span> <span class="n">library_path</span> <span class="o">/</span> <span class="p">(</span><span class="n">library_path</span><span class="o">.</span><span class="n">name</span> <span class="o">+</span> <span class="s1">&#39;.nim&#39;</span><span class="p">)</span>

        <span class="k">if</span> <span class="n">library</span> <span class="ow">and</span> <span class="ow">not</span> <span class="nb">any</span><span class="p">(</span><span class="n">library_path</span><span class="o">.</span><span class="n">glob</span><span class="p">(</span><span class="s1">&#39;*.nimble&#39;</span><span class="p">)):</span>
            <span class="k">raise</span> <span class="n">NimporterException</span><span class="p">(</span>
            <span class="sa">f</span><span class="s2">&quot;Library: </span><span class="si">{library_path}</span><span class="s2"> doesn&#39;t contain a .nimble file&quot;</span>
        <span class="p">)</span>

        <span class="bp">cls</span><span class="o">.</span><span class="n">ensure_nimpy</span><span class="p">()</span>
        <span class="n">switch_file</span> <span class="o">=</span> <span class="n">library_path</span> <span class="o">/</span> <span class="s1">&#39;switches.py&#39;</span>

        <span class="c1"># Switches file found</span>
        <span class="k">if</span> <span class="n">switch_file</span><span class="o">.</span><span class="n">exists</span><span class="p">():</span>
            <span class="n">switches</span> <span class="o">=</span> <span class="bp">cls</span><span class="o">.</span><span class="n">get_switches</span><span class="p">(</span>
                <span class="n">switch_file</span><span class="p">,</span>
                <span class="n">MODULE_PATH</span><span class="o">=</span><span class="n">module_path</span><span class="p">,</span>
                <span class="n">BUILD_ARTIFACT</span><span class="o">=</span><span class="n">build_artifact</span><span class="p">,</span>
                <span class="n">BUILD_DIR</span><span class="o">=</span><span class="kc">None</span><span class="p">,</span>  <span class="c1"># Necessary for import/bundle compatibility</span>
                <span class="n">IS_LIBRARY</span><span class="o">=</span><span class="n">library</span>
            <span class="p">)</span>
            <span class="n">nim_args</span> <span class="o">=</span> <span class="n">switches</span><span class="p">[</span><span class="s1">&#39;import&#39;</span><span class="p">]</span>

        <span class="c1"># Use standard switches</span>
        <span class="k">else</span><span class="p">:</span>
            <span class="n">exe</span> <span class="o">=</span> <span class="p">[(</span><span class="s1">&#39;nimble&#39;</span> <span class="k">if</span> <span class="n">library</span> <span class="k">else</span> <span class="s1">&#39;nim&#39;</span><span class="p">),</span> <span class="s1">&#39;c&#39;</span><span class="p">]</span>
            <span class="n">nim_args</span> <span class="o">=</span> <span class="p">(</span>
                <span class="n">exe</span> <span class="o">+</span> <span class="bp">cls</span><span class="o">.</span><span class="n">NIM_CLI_ARGS</span> <span class="o">+</span>
                <span class="p">[</span><span class="sa">f</span><span class="s1">&#39;--out:</span><span class="si">{build_artifact}</span><span class="s1">&#39;</span><span class="p">,</span> <span class="sa">f</span><span class="s1">&#39;</span><span class="si">{module_path}</span><span class="s1">&#39;</span><span class="p">]</span> <span class="o">+</span>
                <span class="p">([</span><span class="s1">&#39;--accept&#39;</span><span class="p">]</span> <span class="k">if</span> <span class="n">library</span> <span class="k">else</span> <span class="p">[])</span>
            <span class="p">)</span>

        <span class="k">with</span> <span class="n">cd</span><span class="p">(</span><span class="n">library_path</span> <span class="k">if</span> <span class="n">library</span> <span class="k">else</span> <span class="n">Path</span><span class="p">(</span><span class="s1">&#39;.&#39;</span><span class="p">))</span> <span class="k">as</span> <span class="n">tmp_cwd</span><span class="p">:</span>
            <span class="n">output</span><span class="p">,</span> <span class="n">errors</span><span class="p">,</span> <span class="n">warnings</span><span class="p">,</span> <span class="n">hints</span> <span class="o">=</span> <span class="bp">cls</span><span class="o">.</span><span class="n">invoke_compiler</span><span class="p">(</span><span class="n">nim_args</span><span class="p">)</span>

        <span class="k">if</span> <span class="n">errors</span><span class="p">:</span>
            <span class="k">if</span> <span class="n">library</span><span class="p">:</span>
                <span class="k">raise</span> <span class="n">NimInvokeException</span><span class="p">(</span><span class="n">tmp_cwd</span><span class="p">,</span> <span class="n">nim_args</span><span class="p">,</span> <span class="n">errors</span><span class="p">,</span> <span class="n">output</span><span class="p">)</span>
            <span class="k">else</span><span class="p">:</span>
                <span class="k">raise</span> <span class="n">NimCompileException</span><span class="p">(</span><span class="n">errors</span><span class="p">[</span><span class="mi">0</span><span class="p">])</span>

        <span class="k">for</span> <span class="n">warn</span> <span class="ow">in</span> <span class="n">warnings</span><span class="p">:</span> <span class="nb">print</span><span class="p">(</span><span class="n">warn</span><span class="p">)</span>

        <span class="k">return</span> <span class="n">build_artifact</span>


<span class="k">class</span> <span class="nc">Nimporter</span><span class="p">:</span>
    <span class="sd">&quot;&quot;&quot;</span>
<span class="sd">    Python module finder purpose-built to find Nim modules on the Python PATH,</span>
<span class="sd">    compile them, hide them within the __pycache__ directory with other compiled</span>
<span class="sd">    Python files, and then return it as a full Python module.</span>
<span class="sd">    This Nimporter can only import Nim modules with procedures exposed via the</span>
<span class="sd">    [Nimpy](https://github.com/yglukhov/nimpy) library acting as a bridge.</span>

<span class="sd">    Atrributes:</span>
<span class="sd">        IGNORE_CACHE(bool): when True, will always trigger a rebuild of any Nim</span>
<span class="sd">            modules. Can be set by the importer of this module.</span>
<span class="sd">    &quot;&quot;&quot;</span>
    <span class="n">IGNORE_CACHE</span> <span class="o">=</span> <span class="kc">False</span>

    <span class="nd">@classmethod</span>
    <span class="k">def</span> <span class="nf">hash_filename</span><span class="p">(</span><span class="bp">cls</span><span class="p">,</span> <span class="n">module_path</span><span class="p">):</span>
        <span class="sd">&quot;&quot;&quot;</span>
<span class="sd">        Gets the filename that should contain a given module&#39;s hash.</span>
<span class="sd">    </span>
<span class="sd">        Args:</span>
<span class="sd">            module_path(Path): the Nim module the hash file pertains to.</span>

<span class="sd">        Returns:</span>
<span class="sd">            The hash filename as a Path.</span>
<span class="sd">        &quot;&quot;&quot;</span>
        <span class="k">return</span> <span class="p">(</span>
            <span class="n">NimCompiler</span><span class="o">.</span><span class="n">pycache_dir</span><span class="p">(</span><span class="n">module_path</span><span class="p">)</span> <span class="o">/</span> <span class="p">(</span><span class="n">module_path</span><span class="o">.</span><span class="n">name</span> <span class="o">+</span> <span class="s1">&#39;.hash&#39;</span><span class="p">)</span>
        <span class="p">)</span>

    <span class="nd">@classmethod</span>
    <span class="k">def</span> <span class="nf">is_cache</span><span class="p">(</span><span class="bp">cls</span><span class="p">,</span> <span class="n">module_path</span><span class="p">):</span>
        <span class="sd">&quot;&quot;&quot;</span>
<span class="sd">        Determines if the `__pycache__` dir for a given Nim module exists.</span>

<span class="sd">        Args:</span>
<span class="sd">            module_path(Path): the Nim module the `__pycache__` dir pertains to.</span>

<span class="sd">        Returns:</span>
<span class="sd">            A bool indicating whether or not a __pycache__ directory exists to</span>
<span class="sd">            store hashes and build artifacts.</span>
<span class="sd">        &quot;&quot;&quot;</span>
        <span class="k">return</span> <span class="n">NimCompiler</span><span class="o">.</span><span class="n">pycache_dir</span><span class="p">(</span><span class="n">module_path</span><span class="p">)</span><span class="o">.</span><span class="n">exists</span><span class="p">()</span>

    <span class="nd">@classmethod</span>
    <span class="k">def</span> <span class="nf">is_hashed</span><span class="p">(</span><span class="bp">cls</span><span class="p">,</span> <span class="n">module_path</span><span class="p">):</span>
        <span class="sd">&quot;&quot;&quot;</span>
<span class="sd">        Determines if a given Nim module has already been hashed.</span>

<span class="sd">        Args:</span>
<span class="sd">            module_path(Path): the Nim module for which to query hash existence.</span>

<span class="sd">        Returns:</span>
<span class="sd">            A bool indicating whether or not a given Nim file has already been</span>
<span class="sd">            hashed.</span>
<span class="sd">        &quot;&quot;&quot;</span>
        <span class="k">return</span> <span class="bp">cls</span><span class="o">.</span><span class="n">hash_filename</span><span class="p">(</span><span class="n">module_path</span><span class="p">)</span><span class="o">.</span><span class="n">exists</span><span class="p">()</span>

    <span class="nd">@classmethod</span>
    <span class="k">def</span> <span class="nf">is_built</span><span class="p">(</span><span class="bp">cls</span><span class="p">,</span> <span class="n">module_path</span><span class="p">):</span>
        <span class="sd">&quot;&quot;&quot;</span>
<span class="sd">        Determines if a given Nim module has already been built.</span>

<span class="sd">        Args:</span>
<span class="sd">            module_path(Path): the Nim module for which to query for artifacts.</span>

<span class="sd">        Returns:</span>
<span class="sd">            A bool indicating whether or not a given Nim file has already been</span>
<span class="sd">            built.</span>
<span class="sd">        &quot;&quot;&quot;</span>
        <span class="k">return</span> <span class="n">NimCompiler</span><span class="o">.</span><span class="n">build_artifact</span><span class="p">(</span><span class="n">module_path</span><span class="p">)</span><span class="o">.</span><span class="n">exists</span><span class="p">()</span>

    <span class="nd">@classmethod</span>
    <span class="k">def</span> <span class="nf">get_hash</span><span class="p">(</span><span class="bp">cls</span><span class="p">,</span> <span class="n">module_path</span><span class="p">):</span>
        <span class="sd">&quot;&quot;&quot;</span>
<span class="sd">        Gathers the hash for a given Nim module.</span>

<span class="sd">        Args:</span>
<span class="sd">            module_path(Path): the Nim module for which to return its hash.</span>

<span class="sd">        Raises:</span>
<span class="sd">            NimporterException: if the module has not yet been hashed.</span>

<span class="sd">        Returns:</span>
<span class="sd">            The bytes of the hash for a given Nim module.</span>
<span class="sd">        &quot;&quot;&quot;</span>
        <span class="k">if</span> <span class="ow">not</span> <span class="bp">cls</span><span class="o">.</span><span class="n">is_hashed</span><span class="p">(</span><span class="n">module_path</span><span class="p">):</span>
            <span class="n">path</span> <span class="o">=</span> <span class="n">module_path</span><span class="o">.</span><span class="n">absolute</span><span class="p">()</span>
            <span class="k">raise</span> <span class="n">NimporterException</span><span class="p">(</span><span class="sa">f</span><span class="s1">&#39;Module </span><span class="si">{path}</span><span class="s1"> has not yet been hashed.&#39;</span><span class="p">)</span>
        <span class="k">return</span> <span class="bp">cls</span><span class="o">.</span><span class="n">hash_filename</span><span class="p">(</span><span class="n">module_path</span><span class="p">)</span><span class="o">.</span><span class="n">read_bytes</span><span class="p">()</span>

    <span class="nd">@classmethod</span>
    <span class="k">def</span> <span class="nf">hash_changed</span><span class="p">(</span><span class="bp">cls</span><span class="p">,</span> <span class="n">module_path</span><span class="p">):</span>
        <span class="sd">&quot;&quot;&quot;</span>
<span class="sd">        Determines if a module has been modified.</span>

<span class="sd">        Args:</span>
<span class="sd">            module_path(Path): the Nim module to check for modification.</span>

<span class="sd">        Returns:</span>
<span class="sd">            A bool indicating whether or not a given Nim file has changed since</span>
<span class="sd">            last hash. If the module has not yet been hashed, returns True.</span>
<span class="sd">        &quot;&quot;&quot;</span>
        <span class="k">if</span> <span class="ow">not</span> <span class="bp">cls</span><span class="o">.</span><span class="n">is_hashed</span><span class="p">(</span><span class="n">module_path</span><span class="p">):</span>
            <span class="k">return</span> <span class="kc">True</span>
        <span class="k">return</span> <span class="bp">cls</span><span class="o">.</span><span class="n">get_hash</span><span class="p">(</span><span class="n">module_path</span><span class="p">)</span> <span class="o">!=</span> <span class="bp">cls</span><span class="o">.</span><span class="n">hash_file</span><span class="p">(</span><span class="n">module_path</span><span class="p">)</span>

    <span class="nd">@staticmethod</span>
    <span class="k">def</span> <span class="nf">hash_file</span><span class="p">(</span><span class="n">module_path</span><span class="p">):</span>
        <span class="sd">&quot;&quot;&quot;</span>
<span class="sd">        Convenience function to hash a given file.</span>

<span class="sd">        Args:</span>
<span class="sd">            module_path(Path): the file to hash.</span>
<span class="sd">        </span>
<span class="sd">        Returns:</span>
<span class="sd">            The hash bytes of the Nim file.</span>
<span class="sd">        &quot;&quot;&quot;</span>
        <span class="n">block_size</span> <span class="o">=</span> <span class="mi">65536</span>
        <span class="n">hasher</span> <span class="o">=</span> <span class="n">hashlib</span><span class="o">.</span><span class="n">md5</span><span class="p">()</span>
        <span class="k">with</span> <span class="n">module_path</span><span class="o">.</span><span class="n">open</span><span class="p">(</span><span class="s1">&#39;rb&#39;</span><span class="p">)</span> <span class="k">as</span> <span class="n">file</span><span class="p">:</span>
            <span class="n">buf</span> <span class="o">=</span> <span class="n">file</span><span class="o">.</span><span class="n">read</span><span class="p">(</span><span class="n">block_size</span><span class="p">)</span>
            <span class="k">while</span> <span class="nb">len</span><span class="p">(</span><span class="n">buf</span><span class="p">)</span> <span class="o">&gt;</span> <span class="mi">0</span><span class="p">:</span>
                <span class="n">hasher</span><span class="o">.</span><span class="n">update</span><span class="p">(</span><span class="n">buf</span><span class="p">)</span>
                <span class="n">buf</span> <span class="o">=</span> <span class="n">file</span><span class="o">.</span><span class="n">read</span><span class="p">(</span><span class="n">block_size</span><span class="p">)</span>
        <span class="k">return</span> <span class="n">hasher</span><span class="o">.</span><span class="n">digest</span><span class="p">()</span>

    <span class="nd">@classmethod</span>
    <span class="k">def</span> <span class="nf">update_hash</span><span class="p">(</span><span class="bp">cls</span><span class="p">,</span> <span class="n">module_path</span><span class="p">):</span>
        <span class="sd">&quot;&quot;&quot;</span>
<span class="sd">        Updates the hash file associated with a given Nim module.</span>

<span class="sd">        This is commonly done after compilation to determine if recompilation is</span>
<span class="sd">        required upon subsequent imports. If the module&#39;s hash file has not yet</span>
<span class="sd">        been created, this method will create it and store it in the</span>
<span class="sd">        `__pycache__` dir for the module.</span>

<span class="sd">        Args:</span>
<span class="sd">            module_path(Path): the module which should have its hash updated.</span>
<span class="sd">        &quot;&quot;&quot;</span>
        <span class="n">hash_file</span> <span class="o">=</span> <span class="bp">cls</span><span class="o">.</span><span class="n">hash_filename</span><span class="p">(</span><span class="n">module_path</span><span class="p">)</span>
        <span class="n">hash_file</span><span class="o">.</span><span class="n">parent</span><span class="o">.</span><span class="n">mkdir</span><span class="p">(</span><span class="n">parents</span><span class="o">=</span><span class="kc">True</span><span class="p">,</span> <span class="n">exist_ok</span><span class="o">=</span><span class="kc">True</span><span class="p">)</span>
        <span class="k">with</span> <span class="n">hash_file</span><span class="o">.</span><span class="n">open</span><span class="p">(</span><span class="s1">&#39;wb&#39;</span><span class="p">)</span> <span class="k">as</span> <span class="n">file</span><span class="p">:</span>
            <span class="n">file</span><span class="o">.</span><span class="n">write</span><span class="p">(</span><span class="bp">cls</span><span class="o">.</span><span class="n">hash_file</span><span class="p">(</span><span class="n">module_path</span><span class="p">))</span>

    <span class="nd">@classmethod</span>
    <span class="k">def</span> <span class="nf">import_nim_module</span><span class="p">(</span><span class="bp">cls</span><span class="p">,</span> <span class="n">fullname</span><span class="p">,</span> <span class="n">path</span><span class="p">:</span><span class="nb">list</span><span class="o">=</span><span class="kc">None</span><span class="p">,</span> <span class="n">ignore_cache</span><span class="o">=</span><span class="kc">None</span><span class="p">):</span>
        <span class="sd">&quot;&quot;&quot;</span>
<span class="sd">        Convenience function to manually import a given Nim module or library.</span>

<span class="sd">        Can be used to explicitly import a module rather than using the `import`</span>
<span class="sd">        keyword. Allows the cache to be ignored to solve issues arising from</span>
<span class="sd">        caching one module when 10 other imported Nim libraries have changed.</span>

<span class="sd">        Example Use:</span>

<span class="sd">            # Rather than:</span>
<span class="sd">            import foo</span>
<span class="sd">            # You can say:</span>
<span class="sd">            foo = Nimporter.import_nim_module(&#39;foo&#39;, [&#39;/some/random/dir&#39;])</span>

<span class="sd">        Args:</span>
<span class="sd">            fullname(str): the module to import. Can be &#39;foo&#39; or &#39;foo.bar.baz&#39;</span>
<span class="sd">            path(list): a list of paths to search first.</span>
<span class="sd">            ignore_cache(bool): whether or not to use a cached build if found.</span>

<span class="sd">        Returns:</span>
<span class="sd">            The Python Module object representing the imported PYD or SO file.            </span>
<span class="sd">        &quot;&quot;&quot;</span>
        <span class="k">if</span> <span class="n">ignore_cache</span> <span class="o">!=</span> <span class="kc">None</span><span class="p">:</span>
            <span class="n">tmp</span> <span class="o">=</span> <span class="bp">cls</span><span class="o">.</span><span class="n">IGNORE_CACHE</span>
            <span class="bp">cls</span><span class="o">.</span><span class="n">IGNORE_CACHE</span> <span class="o">=</span> <span class="n">ignore_cache</span>

        <span class="k">try</span><span class="p">:</span>
            <span class="n">spec</span> <span class="o">=</span> <span class="p">(</span>
                <span class="bp">cls</span><span class="o">.</span><span class="n">import_nim_code</span><span class="p">(</span><span class="n">fullname</span><span class="p">,</span> <span class="n">path</span><span class="p">,</span> <span class="n">library</span><span class="o">=</span><span class="kc">False</span><span class="p">)</span>
                <span class="ow">or</span>
                <span class="bp">cls</span><span class="o">.</span><span class="n">import_nim_code</span><span class="p">(</span><span class="n">fullname</span><span class="p">,</span> <span class="n">path</span><span class="p">,</span> <span class="n">library</span><span class="o">=</span><span class="kc">True</span><span class="p">)</span>
            <span class="p">)</span>
        <span class="k">finally</span><span class="p">:</span>
            <span class="k">if</span> <span class="n">ignore_cache</span> <span class="o">!=</span> <span class="kc">None</span><span class="p">:</span>
                <span class="bp">cls</span><span class="o">.</span><span class="n">IGNORE_CACHE</span> <span class="o">=</span> <span class="n">tmp</span>

        <span class="k">if</span> <span class="ow">not</span> <span class="n">spec</span><span class="p">:</span>
            <span class="k">raise</span> <span class="ne">ImportError</span><span class="p">(</span><span class="sa">f</span><span class="s1">&#39;No module named </span><span class="si">{fullname}</span><span class="s1">&#39;</span><span class="p">)</span>

        <span class="n">module</span> <span class="o">=</span> <span class="n">spec</span><span class="o">.</span><span class="n">loader</span><span class="o">.</span><span class="n">create_module</span><span class="p">(</span><span class="n">spec</span><span class="p">)</span>
        <span class="k">return</span> <span class="n">module</span>

    <span class="nd">@classmethod</span>
    <span class="k">def</span> <span class="nf">import_nim_code</span><span class="p">(</span><span class="bp">cls</span><span class="p">,</span> <span class="n">fullname</span><span class="p">,</span> <span class="n">path</span><span class="p">,</span> <span class="o">*</span><span class="p">,</span> <span class="n">library</span><span class="p">:</span> <span class="nb">bool</span><span class="p">):</span>
        <span class="sd">&quot;&quot;&quot;</span>
<span class="sd">        Search for, compile, and return Spec for module loaders.</span>

<span class="sd">        Used by both NimModImporter and NimLibImporter for their Spec-finding</span>
<span class="sd">        capabilities.</span>

<span class="sd">        Args:</span>
<span class="sd">            fullname(str): the name given when importing the module in Python.</span>
<span class="sd">            path(list): additional search paths.</span>
<span class="sd">            library(bool): indicates whether or not to compile as a library.</span>

<span class="sd">        Returns:</span>
<span class="sd">            A Spec object that can be used to import the (now compiled) Nim</span>
<span class="sd">            module or library.</span>
<span class="sd">        &quot;&quot;&quot;</span>
        <span class="n">parts</span> <span class="o">=</span> <span class="n">fullname</span><span class="o">.</span><span class="n">split</span><span class="p">(</span><span class="s1">&#39;.&#39;</span><span class="p">)</span>
        <span class="n">module</span> <span class="o">=</span> <span class="n">parts</span><span class="p">[</span><span class="o">-</span><span class="mi">1</span><span class="p">]</span> <span class="k">if</span> <span class="n">library</span> <span class="k">else</span> <span class="n">parts</span><span class="o">.</span><span class="n">pop</span><span class="p">()</span>
        <span class="n">module_file</span> <span class="o">=</span> <span class="sa">f</span><span class="s1">&#39;</span><span class="si">{module}</span><span class="s1">.nim&#39;</span>
        <span class="n">path</span> <span class="o">=</span> <span class="nb">list</span><span class="p">(</span><span class="n">path</span><span class="p">)</span> <span class="k">if</span> <span class="n">path</span> <span class="k">else</span> <span class="p">[]</span>  <span class="c1"># Ensure that path is always a list</span>

        <span class="c1"># NOTE(pebaz): Package is different based only on `library`</span>
        <span class="n">package</span> <span class="o">=</span> <span class="s1">&#39;/&#39;</span><span class="o">.</span><span class="n">join</span><span class="p">(</span><span class="n">parts</span><span class="p">)</span>

        <span class="n">search_paths</span> <span class="o">=</span> <span class="p">{</span>
            <span class="n">Path</span><span class="p">(</span><span class="n">i</span><span class="p">)</span>
            <span class="k">for</span> <span class="n">i</span> <span class="ow">in</span> <span class="p">(</span><span class="n">path</span> <span class="o">+</span> <span class="n">sys</span><span class="o">.</span><span class="n">path</span> <span class="o">+</span> <span class="p">[</span><span class="s1">&#39;.&#39;</span><span class="p">])</span>
            <span class="k">if</span> <span class="n">Path</span><span class="p">(</span><span class="n">i</span><span class="p">)</span><span class="o">.</span><span class="n">is_dir</span><span class="p">()</span>
        <span class="p">}</span>

        <span class="k">for</span> <span class="n">search_path</span> <span class="ow">in</span> <span class="n">search_paths</span><span class="p">:</span>
            <span class="n">spath</span> <span class="o">=</span> <span class="p">(</span><span class="n">search_path</span> <span class="o">/</span> <span class="n">package</span><span class="p">)</span><span class="o">.</span><span class="n">resolve</span><span class="p">()</span>

            <span class="c1"># Derive module path regardless of library or module</span>

            <span class="k">if</span> <span class="n">library</span> <span class="ow">and</span> <span class="ow">not</span> <span class="nb">any</span><span class="p">(</span><span class="n">spath</span><span class="o">.</span><span class="n">glob</span><span class="p">(</span><span class="s1">&#39;*.nimble&#39;</span><span class="p">)):</span> <span class="k">continue</span>

            <span class="n">module_path</span> <span class="o">=</span> <span class="n">spath</span> <span class="o">/</span> <span class="n">module_file</span>

            <span class="k">if</span> <span class="ow">not</span> <span class="n">module_path</span><span class="o">.</span><span class="n">exists</span><span class="p">():</span> <span class="k">continue</span>

            <span class="n">build_artifact</span> <span class="o">=</span> <span class="n">NimCompiler</span><span class="o">.</span><span class="n">build_artifact</span><span class="p">(</span><span class="n">module_path</span><span class="p">)</span>

            <span class="k">if</span> <span class="bp">cls</span><span class="o">.</span><span class="n">should_compile</span><span class="p">(</span><span class="n">module_path</span><span class="p">):</span>
                <span class="n">NimCompiler</span><span class="o">.</span><span class="n">compile_nim_code</span><span class="p">(</span>
                    <span class="n">module_path</span><span class="o">.</span><span class="n">parent</span> <span class="k">if</span> <span class="n">library</span> <span class="k">else</span> <span class="n">module_path</span><span class="p">,</span>
                    <span class="n">build_artifact</span><span class="p">,</span>
                    <span class="n">library</span><span class="o">=</span><span class="n">library</span>
                <span class="p">)</span>

                <span class="bp">cls</span><span class="o">.</span><span class="n">update_hash</span><span class="p">(</span><span class="n">module_path</span><span class="p">)</span>
            
            <span class="k">return</span> <span class="n">util</span><span class="o">.</span><span class="n">spec_from_file_location</span><span class="p">(</span>
                <span class="n">fullname</span><span class="p">,</span>
                <span class="n">location</span><span class="o">=</span><span class="nb">str</span><span class="p">(</span><span class="n">build_artifact</span><span class="o">.</span><span class="n">absolute</span><span class="p">())</span>
            <span class="p">)</span>

    <span class="nd">@classmethod</span>
    <span class="k">def</span> <span class="nf">should_compile</span><span class="p">(</span><span class="bp">cls</span><span class="p">,</span> <span class="n">module_path</span><span class="p">):</span>
        <span class="sd">&quot;&quot;&quot;</span>
<span class="sd">        Determines if a module should be rebuilt using only the path to it.</span>

<span class="sd">        Factors included in the decision to compile a module include: </span>

<span class="sd">         * If `IGNORE_CACHE` is set</span>
<span class="sd">         * If the module has been modified since the last build</span>
<span class="sd">         * If the `__pycache__` directory does not exist</span>
<span class="sd">         * If there is no cached build artifact available in `__pycache__`</span>

<span class="sd">        Args:</span>
<span class="sd">            module_path(Path): the Nim module to potentially (re)compile.</span>

<span class="sd">        Returns:</span>
<span class="sd">            A bool indicating whether or not the module should be (re)built.</span>
<span class="sd">        &quot;&quot;&quot;</span>
        <span class="k">return</span> <span class="nb">any</span><span class="p">([</span>
            <span class="bp">cls</span><span class="o">.</span><span class="n">IGNORE_CACHE</span><span class="p">,</span>
            <span class="bp">cls</span><span class="o">.</span><span class="n">hash_changed</span><span class="p">(</span><span class="n">module_path</span><span class="p">),</span>
            <span class="ow">not</span> <span class="bp">cls</span><span class="o">.</span><span class="n">is_cache</span><span class="p">(</span><span class="n">module_path</span><span class="p">),</span>
            <span class="ow">not</span> <span class="bp">cls</span><span class="o">.</span><span class="n">is_built</span><span class="p">(</span><span class="n">module_path</span><span class="p">)</span>
        <span class="p">])</span>

    <span class="nd">@classmethod</span>
    <span class="k">def</span> <span class="nf">_find_extensions</span><span class="p">(</span><span class="bp">cls</span><span class="p">,</span> <span class="n">path</span><span class="p">,</span> <span class="n">exclude_dirs</span><span class="o">=</span><span class="nb">set</span><span class="p">()):</span>
        <span class="sd">&quot;&quot;&quot;</span>
<span class="sd">        Recurses through a given path to find all Nim modules or libraries.</span>

<span class="sd">        Args:</span>
<span class="sd">            path(Path): the path to begin recursing.</span>
<span class="sd">            exclude_dirs(list): the list of Paths to skip while searching.</span>

<span class="sd">        Returns:</span>
<span class="sd">            A list of Path objects. File Paths indicate a Nim Module. Folder</span>
<span class="sd">            Paths indicate Nim Libraries.</span>
<span class="sd">        &quot;&quot;&quot;</span>
        <span class="n">exclude_dirs</span> <span class="o">=</span> <span class="p">{</span><span class="n">p</span><span class="o">.</span><span class="n">expanduser</span><span class="p">()</span><span class="o">.</span><span class="n">absolute</span><span class="p">()</span> <span class="k">for</span> <span class="n">i</span> <span class="ow">in</span> <span class="n">exclude_dirs</span><span class="p">}</span>
        <span class="n">nim_exts</span> <span class="o">=</span> <span class="p">[]</span>

        <span class="k">for</span> <span class="n">item</span> <span class="ow">in</span> <span class="n">path</span><span class="o">.</span><span class="n">iterdir</span><span class="p">():</span>
            <span class="k">if</span> <span class="n">item</span><span class="o">.</span><span class="n">expanduser</span><span class="p">()</span><span class="o">.</span><span class="n">absolute</span><span class="p">()</span> <span class="ow">in</span> <span class="n">exclude_dirs</span><span class="p">:</span>
                <span class="k">continue</span>

            <span class="k">if</span> <span class="n">item</span><span class="o">.</span><span class="n">is_dir</span><span class="p">()</span> <span class="ow">and</span> <span class="nb">list</span><span class="p">(</span><span class="n">item</span><span class="o">.</span><span class="n">glob</span><span class="p">(</span><span class="s1">&#39;*.nimble&#39;</span><span class="p">)):</span>
                <span class="c1"># Treat directory as one single Extension</span>
                <span class="p">(</span><span class="n">nimble_file</span><span class="p">,)</span> <span class="o">=</span> <span class="n">item</span><span class="o">.</span><span class="n">glob</span><span class="p">(</span><span class="s1">&#39;*.nimble&#39;</span><span class="p">)</span>
                <span class="n">nim_file</span> <span class="o">=</span> <span class="n">nimble_file</span><span class="o">.</span><span class="n">parent</span> <span class="o">/</span> <span class="p">(</span><span class="n">nimble_file</span><span class="o">.</span><span class="n">stem</span> <span class="o">+</span> <span class="s1">&#39;.nim&#39;</span><span class="p">)</span>

                <span class="c1"># NOTE(pebaz): Folder must contain Nim file of exact same name.</span>
                <span class="k">if</span> <span class="n">nim_file</span><span class="o">.</span><span class="n">exists</span><span class="p">():</span>
                    <span class="n">nim_exts</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">item</span><span class="p">)</span>

            <span class="k">elif</span> <span class="n">item</span><span class="o">.</span><span class="n">is_dir</span><span class="p">():</span>
                <span class="c1"># Treat item as directory</span>
                <span class="n">nim_exts</span><span class="o">.</span><span class="n">extend</span><span class="p">(</span>
                    <span class="bp">cls</span><span class="o">.</span><span class="n">_find_extensions</span><span class="p">(</span><span class="n">item</span><span class="p">,</span> <span class="n">exclude_dirs</span><span class="o">=</span><span class="n">exclude_dirs</span><span class="p">)</span>
                <span class="p">)</span>

            <span class="k">elif</span> <span class="n">item</span><span class="o">.</span><span class="n">suffix</span> <span class="o">==</span> <span class="s1">&#39;.nim&#39;</span><span class="p">:</span>
                <span class="c1"># Treat item as a Nim Extension.</span>
                <span class="n">nim_exts</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">item</span><span class="p">)</span>

        <span class="k">return</span> <span class="n">nim_exts</span>

    <span class="nd">@classmethod</span>
    <span class="k">def</span> <span class="nf">_build_nim_extension</span><span class="p">(</span><span class="bp">cls</span><span class="p">,</span> <span class="n">path</span><span class="p">,</span> <span class="n">root</span><span class="p">):</span>
        <span class="sd">&quot;&quot;&quot;</span>
<span class="sd">        Convenience function to create an Extension object from a given path.</span>

<span class="sd">        Args:</span>
<span class="sd">            path(Path): the path to the Nim module/library.</span>
<span class="sd">            root(tuple): the namespace to add the Extension to.</span>

<span class="sd">        Returns:</span>
<span class="sd">            An Extension object representing the Nim module or library that has</span>
<span class="sd">            successfully be compiled to C.</span>
<span class="sd">        &quot;&quot;&quot;</span>
        <span class="k">return</span> <span class="n">NimCompiler</span><span class="o">.</span><span class="n">compile_nim_extension</span><span class="p">(</span>
            <span class="n">path</span><span class="p">,</span> <span class="n">root</span><span class="p">,</span> <span class="n">library</span><span class="o">=</span><span class="n">path</span><span class="o">.</span><span class="n">is_dir</span><span class="p">()</span>
        <span class="p">)</span>

    <span class="nd">@classmethod</span>
    <span class="k">def</span> <span class="nf">check_nim_extensions</span><span class="p">(</span><span class="bp">cls</span><span class="p">,</span> <span class="n">root</span><span class="p">):</span>
        <span class="sd">&quot;&quot;&quot;</span>
<span class="sd">        if not cls.check_nim_extensions(root):</span>
<span class="sd">            ...</span>
<span class="sd">        else:</span>
<span class="sd">            extensions = cls.get_nim_extensions(root)</span>
<span class="sd">        &quot;&quot;&quot;</span>
        <span class="k">return</span> <span class="p">(</span><span class="n">root</span> <span class="o">/</span> <span class="n">NimCompiler</span><span class="o">.</span><span class="n">EXT_DIR</span><span class="p">)</span><span class="o">.</span><span class="n">exists</span><span class="p">()</span>

    <span class="nd">@classmethod</span>
    <span class="k">def</span> <span class="nf">get_nim_extensions</span><span class="p">(</span><span class="bp">cls</span><span class="p">,</span> <span class="n">root</span><span class="p">):</span>
        <span class="sd">&quot;&quot;&quot;</span>
<span class="sd">        Convenience function to look for previously compiled Nim Extensions.</span>

<span class="sd">        When extensions are created, they are stored in the</span>
<span class="sd">        `&lt;root&gt;/build/nim-extensions` directory. The reason this is necessary is</span>
<span class="sd">        because `setup.py` runs the `setup()` function twice: once to gather</span>
<span class="sd">        info and once to actually compile/bundle everything. On the first pass,</span>
<span class="sd">        the extensions are compiled to C. On the second pass, they are compiled</span>
<span class="sd">        to Python-compatible shared objects.</span>

<span class="sd">        Args:</span>
<span class="sd">            root(Path): the root of the project.</span>

<span class="sd">        Returns:</span>
<span class="sd">            A list of Extensions that were compiled on the library maintainer&#39;s</span>
<span class="sd">            computer.</span>
<span class="sd">        &quot;&quot;&quot;</span>
        <span class="n">extension_dir</span> <span class="o">=</span> <span class="n">root</span> <span class="o">/</span> <span class="n">NimCompiler</span><span class="o">.</span><span class="n">EXT_DIR</span>
        <span class="k">assert</span> <span class="n">extension_dir</span><span class="o">.</span><span class="n">exists</span><span class="p">()</span>
        <span class="k">return</span> <span class="p">[</span>
            <span class="n">Extension</span><span class="p">(</span>
                <span class="n">name</span><span class="o">=</span><span class="n">extension</span><span class="o">.</span><span class="n">name</span><span class="p">,</span>
                <span class="n">sources</span><span class="o">=</span><span class="p">[</span><span class="nb">str</span><span class="p">(</span><span class="n">c</span><span class="o">.</span><span class="n">absolute</span><span class="p">())</span> <span class="k">for</span> <span class="n">c</span> <span class="ow">in</span> <span class="n">extension</span><span class="o">.</span><span class="n">glob</span><span class="p">(</span><span class="s1">&#39;*.c&#39;</span><span class="p">)],</span>
                <span class="n">include_dirs</span><span class="o">=</span><span class="p">[</span><span class="nb">str</span><span class="p">(</span><span class="n">extension</span><span class="o">.</span><span class="n">absolute</span><span class="p">())]</span>
            <span class="p">)</span>
            <span class="k">for</span> <span class="n">extension</span> <span class="ow">in</span> <span class="n">extension_dir</span><span class="o">.</span><span class="n">iterdir</span><span class="p">()</span>
        <span class="p">]</span>

    <span class="nd">@classmethod</span>
    <span class="k">def</span> <span class="nf">build_nim_extensions</span><span class="p">(</span><span class="bp">cls</span><span class="p">,</span> <span class="n">root</span><span class="o">=</span><span class="kc">None</span><span class="p">,</span> <span class="n">exclude_dirs</span><span class="o">=</span><span class="p">[]):</span>
        <span class="sd">&quot;&quot;&quot;</span>
<span class="sd">        Gathers all Nim Extensions by recursing through a Python project.</span>

<span class="sd">        Compiles Nim modules and libraries to C and creates Extensions from them</span>
<span class="sd">        for source, binary, or wheel distribution.</span>

<span class="sd">        Automatically recurses through the project directory to find all the Nim</span>
<span class="sd">        modules and Nim libraries.</span>

<span class="sd">        NOTE: Since this method is the only method that should be used by</span>
<span class="sd">        consumers of the Nimporter API, it has to do a couple of things:</span>

<span class="sd">        1. Build all Nim modules and libraries into C Extensions.</span>
<span class="sd">        2. Compile all C Extensions with a C compiler on an end-user&#39;s machine.</span>

<span class="sd">        Case 1 happens when creating a source or binary distribution. Also, this</span>
<span class="sd">        can happen if installing via: `python setup.py install` after cloning</span>
<span class="sd">        from Git.</span>

<span class="sd">        Case 2 happens after the C files have been put into the source archive</span>
<span class="sd">        and shipped to the end user. When the end user runs the `setup()`</span>
<span class="sd">        function, the already-bundled C files need to be compiled as Extensions</span>
<span class="sd">        rather than trying to look for Nim files that have not been bundled.</span>

<span class="sd">        Although this is a complicated process, it can be illustrated here:</span>

<span class="sd">        * `python setup.py install`: Case 1 + 2</span>
<span class="sd">        * `pip install some-lib`: Case 2</span>
<span class="sd">        * `pip install git+https://github.com/some-lib`: Case 1 + 2</span>

<span class="sd">        Args:</span>
<span class="sd">            root(tuple): the namespace to add all extensions to.</span>
<span class="sd">            exclude_dirs(list): the Paths to skip while recursing the project.</span>

<span class="sd">        Returns:</span>
<span class="sd">            A list of Extensions that can be added to the setup() function&#39;s</span>
<span class="sd">            &quot;ext_modules&quot; keyword argument.</span>
<span class="sd">        &quot;&quot;&quot;</span>
        <span class="c1">#root = (root or Path()).expanduser().absolute()</span>
        <span class="n">root</span> <span class="o">=</span> <span class="n">root</span> <span class="ow">or</span> <span class="n">Path</span><span class="p">()</span>

        <span class="c1"># Check for bundled C source files</span>
        <span class="k">if</span> <span class="bp">cls</span><span class="o">.</span><span class="n">check_nim_extensions</span><span class="p">(</span><span class="n">root</span><span class="p">):</span>

            <span class="c1"># NOTE(pebaz): Run only on end-user&#39;s machine.</span>
            <span class="k">return</span> <span class="bp">cls</span><span class="o">.</span><span class="n">get_nim_extensions</span><span class="p">(</span><span class="n">root</span><span class="p">)</span>

        <span class="n">extensions</span> <span class="o">=</span> <span class="p">[]</span>

        <span class="c1"># Create extensions from the Nim files found within the project</span>
        <span class="k">for</span> <span class="n">extension</span> <span class="ow">in</span> <span class="bp">cls</span><span class="o">.</span><span class="n">_find_extensions</span><span class="p">(</span><span class="n">root</span><span class="p">,</span> <span class="n">exclude_dirs</span><span class="p">):</span>

            <span class="c1"># NOTE(pebaz): Run on author&#39;s machine or when building from source</span>
            <span class="n">ext</span> <span class="o">=</span> <span class="bp">cls</span><span class="o">.</span><span class="n">_build_nim_extension</span><span class="p">(</span><span class="n">extension</span><span class="p">,</span> <span class="n">root</span><span class="p">)</span>
            <span class="k">if</span> <span class="n">ext</span><span class="p">:</span> <span class="n">extensions</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">ext</span><span class="p">)</span>

        <span class="k">return</span> <span class="n">extensions</span>


<span class="k">def</span> <span class="nf">register_importer</span><span class="p">(</span><span class="n">list_position</span><span class="p">):</span>
    <span class="sd">&quot;&quot;&quot;</span>
<span class="sd">    Adds a given importer class to `sys.meta_path` at a given position.</span>

<span class="sd">    NOTE: The position in `sys.meta_path` is extremely relevant.</span>

<span class="sd">    Args:</span>
<span class="sd">        list_position(int): the index in `sys.meta_path` to place the importer.</span>
<span class="sd">    &quot;&quot;&quot;</span>
    <span class="k">def</span> <span class="nf">decorator</span><span class="p">(</span><span class="n">importer</span><span class="p">):</span>
        <span class="k">nonlocal</span> <span class="n">list_position</span>

        <span class="c1"># Make the list_position act like how a list is normally indexed</span>
        <span class="k">if</span> <span class="n">list_position</span> <span class="o">&lt;</span> <span class="mi">0</span><span class="p">:</span>
            <span class="n">list_position</span> <span class="o">=</span> <span class="nb">len</span><span class="p">(</span><span class="n">sys</span><span class="o">.</span><span class="n">meta_path</span><span class="p">)</span> <span class="o">+</span> <span class="mi">1</span> <span class="o">-</span> <span class="n">list_position</span>
 
        <span class="n">sys</span><span class="o">.</span><span class="n">meta_path</span><span class="o">.</span><span class="n">insert</span><span class="p">(</span><span class="n">list_position</span><span class="p">,</span> <span class="n">importer</span><span class="p">)</span>

        <span class="c1"># Ensure that Nim files won&#39;t be passed up because of other Importers.</span>
        <span class="n">sys</span><span class="o">.</span><span class="n">path_importer_cache</span><span class="o">.</span><span class="n">clear</span><span class="p">()</span>
        <span class="n">importlib</span><span class="o">.</span><span class="n">invalidate_caches</span><span class="p">()</span>

        <span class="k">return</span> <span class="n">importer</span>
    <span class="k">return</span> <span class="n">decorator</span>


<span class="nd">@register_importer</span><span class="p">(</span><span class="o">-</span><span class="mi">1</span><span class="p">)</span>
<span class="k">class</span> <span class="nc">NimModImporter</span><span class="p">:</span>
    <span class="sd">&quot;&quot;&quot;</span>
<span class="sd">    Extends Python import machinery to be able to import Nim modules.</span>

<span class="sd">    NOTE: Must be placed at the back of `sys.meta_path` because Python modules</span>
<span class="sd">    should be given precedence over Nim modules.</span>

<span class="sd">    Nim Modules can be placed anywhere that Python modules can. However, if a</span>
<span class="sd">    Python module and a Nim module with the same name are in the same package,</span>
<span class="sd">    the Python module will be imported.</span>
<span class="sd">    &quot;&quot;&quot;</span>

    <span class="nd">@classmethod</span>
    <span class="k">def</span> <span class="nf">find_spec</span><span class="p">(</span><span class="bp">cls</span><span class="p">,</span> <span class="n">fullname</span><span class="p">,</span> <span class="n">path</span><span class="o">=</span><span class="kc">None</span><span class="p">,</span> <span class="n">target</span><span class="o">=</span><span class="kc">None</span><span class="p">):</span>
        <span class="k">return</span> <span class="n">Nimporter</span><span class="o">.</span><span class="n">import_nim_code</span><span class="p">(</span><span class="n">fullname</span><span class="p">,</span> <span class="n">path</span><span class="p">,</span> <span class="n">library</span><span class="o">=</span><span class="kc">False</span><span class="p">)</span>


<span class="nd">@register_importer</span><span class="p">(</span><span class="mi">0</span><span class="p">)</span>
<span class="k">class</span> <span class="nc">NimLibImporter</span><span class="p">:</span>
    <span class="sd">&quot;&quot;&quot;</span>
<span class="sd">    Extends Python import machinery to be able to import Nim libraries.</span>

<span class="sd">    NOTE: Must be placed at the front of `sys.meta_path` because of how Python</span>
<span class="sd">    treats folders when imported.</span>

<span class="sd">    Before NimLibImporter can attempt to find a folder containing a Nimble file</span>
<span class="sd">    containing dependency info and a corresponding Nim module, Python&#39;s import</span>
<span class="sd">    machinery imports the folder as a `namspace` type.</span>

<span class="sd">    The only way to allow NimLibImporter to get a chance to import Nim libraries</span>
<span class="sd">    is to put it at the front of `sys.meta_path`. However, this has a small side</span>
<span class="sd">    effect of making Nim libraries have precedence over Python namespaces.</span>

<span class="sd">    This should never have any adverse effects since the criterion for a Nim</span>
<span class="sd">    library in relation to Nimporter is to have a folder containing a Nim module</span>
<span class="sd">    and a Nimble file with the same name as the folder. By placing both of those</span>
<span class="sd">    files into a directory, it should be extremely clear that the given folder</span>
<span class="sd">    is a Nim library.</span>

<span class="sd">    Additionally, this also means that a Nim library cannot contain any Python</span>
<span class="sd">    modules.</span>
<span class="sd">    &quot;&quot;&quot;</span>

    <span class="nd">@classmethod</span>
    <span class="k">def</span> <span class="nf">find_spec</span><span class="p">(</span><span class="bp">cls</span><span class="p">,</span> <span class="n">fullname</span><span class="p">,</span> <span class="n">path</span><span class="o">=</span><span class="kc">None</span><span class="p">,</span> <span class="n">target</span><span class="o">=</span><span class="kc">None</span><span class="p">):</span>
        <span class="k">return</span> <span class="n">Nimporter</span><span class="o">.</span><span class="n">import_nim_code</span><span class="p">(</span><span class="n">fullname</span><span class="p">,</span> <span class="n">path</span><span class="p">,</span> <span class="n">library</span><span class="o">=</span><span class="kc">True</span><span class="p">)</span>


<span class="c1"># This should be the only real usage of the Nimporter module beyond importing it</span>
<span class="n">build_nim_extensions</span> <span class="o">=</span> <span class="n">Nimporter</span><span class="o">.</span><span class="n">build_nim_extensions</span>
</pre></div>

  </div>

  </header>

  <section id="section-items">

    <h2 class="section-title" id="header-functions">Functions</h2>
      
  <div class="item">
    <div class="name def" id="nimporter.build_nim_extensions">
    <p>def <span class="ident">build_nim_extensions</span>(</p><p>cls, root=None, exclude_dirs=[])</p>
    </div>
    

    
  
    <div class="desc"><p>Gathers all Nim Extensions by recursing through a Python project.</p>
<p>Compiles Nim modules and libraries to C and creates Extensions from them
for source, binary, or wheel distribution.</p>
<p>Automatically recurses through the project directory to find all the Nim
modules and Nim libraries.</p>
<p>NOTE: Since this method is the only method that should be used by
consumers of the Nimporter API, it has to do a couple of things:</p>
<ol>
<li>Build all Nim modules and libraries into C Extensions.</li>
<li>Compile all C Extensions with a C compiler on an end-user's machine.</li>
</ol>
<p>Case 1 happens when creating a source or binary distribution. Also, this
can happen if installing via: <code>python setup.py install</code> after cloning
from Git.</p>
<p>Case 2 happens after the C files have been put into the source archive
and shipped to the end user. When the end user runs the <code>setup()</code>
function, the already-bundled C files need to be compiled as Extensions
rather than trying to look for Nim files that have not been bundled.</p>
<p>Although this is a complicated process, it can be illustrated here:</p>
<ul>
<li><code>python setup.py install</code>: Case 1 + 2</li>
<li><code>pip install some-lib</code>: Case 2</li>
<li><code>pip install git+https://github.com/some-lib</code>: Case 1 + 2</li>
</ul>
<p>Args:
    root(tuple): the namespace to add all extensions to.
    exclude_dirs(list): the Paths to skip while recursing the project.</p>
<p>Returns:
    A list of Extensions that can be added to the setup() function's
    "ext_modules" keyword argument.</p></div>
  <div class="source_cont">
  <p class="source_link"><a href="javascript:void(0);" onclick="toggle('source-nimporter.build_nim_extensions', this);">Show source &equiv;</a></p>
  <div id="source-nimporter.build_nim_extensions" class="source">
    <div class="codehilite"><pre><span></span><span class="nd">@classmethod</span>
<span class="k">def</span> <span class="nf">build_nim_extensions</span><span class="p">(</span><span class="bp">cls</span><span class="p">,</span> <span class="n">root</span><span class="o">=</span><span class="kc">None</span><span class="p">,</span> <span class="n">exclude_dirs</span><span class="o">=</span><span class="p">[]):</span>
    <span class="sd">&quot;&quot;&quot;</span>
<span class="sd">    Gathers all Nim Extensions by recursing through a Python project.</span>
<span class="sd">    Compiles Nim modules and libraries to C and creates Extensions from them</span>
<span class="sd">    for source, binary, or wheel distribution.</span>
<span class="sd">    Automatically recurses through the project directory to find all the Nim</span>
<span class="sd">    modules and Nim libraries.</span>
<span class="sd">    NOTE: Since this method is the only method that should be used by</span>
<span class="sd">    consumers of the Nimporter API, it has to do a couple of things:</span>
<span class="sd">    1. Build all Nim modules and libraries into C Extensions.</span>
<span class="sd">    2. Compile all C Extensions with a C compiler on an end-user&#39;s machine.</span>
<span class="sd">    Case 1 happens when creating a source or binary distribution. Also, this</span>
<span class="sd">    can happen if installing via: `python setup.py install` after cloning</span>
<span class="sd">    from Git.</span>
<span class="sd">    Case 2 happens after the C files have been put into the source archive</span>
<span class="sd">    and shipped to the end user. When the end user runs the `setup()`</span>
<span class="sd">    function, the already-bundled C files need to be compiled as Extensions</span>
<span class="sd">    rather than trying to look for Nim files that have not been bundled.</span>
<span class="sd">    Although this is a complicated process, it can be illustrated here:</span>
<span class="sd">    * `python setup.py install`: Case 1 + 2</span>
<span class="sd">    * `pip install some-lib`: Case 2</span>
<span class="sd">    * `pip install git+https://github.com/some-lib`: Case 1 + 2</span>
<span class="sd">    Args:</span>
<span class="sd">        root(tuple): the namespace to add all extensions to.</span>
<span class="sd">        exclude_dirs(list): the Paths to skip while recursing the project.</span>
<span class="sd">    Returns:</span>
<span class="sd">        A list of Extensions that can be added to the setup() function&#39;s</span>
<span class="sd">        &quot;ext_modules&quot; keyword argument.</span>
<span class="sd">    &quot;&quot;&quot;</span>
    <span class="c1">#root = (root or Path()).expanduser().absolute()</span>
    <span class="n">root</span> <span class="o">=</span> <span class="n">root</span> <span class="ow">or</span> <span class="n">Path</span><span class="p">()</span>
    <span class="c1"># Check for bundled C source files</span>
    <span class="k">if</span> <span class="bp">cls</span><span class="o">.</span><span class="n">check_nim_extensions</span><span class="p">(</span><span class="n">root</span><span class="p">):</span>
        <span class="c1"># NOTE(pebaz): Run only on end-user&#39;s machine.</span>
        <span class="k">return</span> <span class="bp">cls</span><span class="o">.</span><span class="n">get_nim_extensions</span><span class="p">(</span><span class="n">root</span><span class="p">)</span>
    <span class="n">extensions</span> <span class="o">=</span> <span class="p">[]</span>
    <span class="c1"># Create extensions from the Nim files found within the project</span>
    <span class="k">for</span> <span class="n">extension</span> <span class="ow">in</span> <span class="bp">cls</span><span class="o">.</span><span class="n">_find_extensions</span><span class="p">(</span><span class="n">root</span><span class="p">,</span> <span class="n">exclude_dirs</span><span class="p">):</span>
        <span class="c1"># NOTE(pebaz): Run on author&#39;s machine or when building from source</span>
        <span class="n">ext</span> <span class="o">=</span> <span class="bp">cls</span><span class="o">.</span><span class="n">_build_nim_extension</span><span class="p">(</span><span class="n">extension</span><span class="p">,</span> <span class="n">root</span><span class="p">)</span>
        <span class="k">if</span> <span class="n">ext</span><span class="p">:</span> <span class="n">extensions</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">ext</span><span class="p">)</span>
    <span class="k">return</span> <span class="n">extensions</span>
</pre></div>

  </div>
</div>

  </div>
  
      
  <div class="item">
    <div class="name def" id="nimporter.cd">
    <p>def <span class="ident">cd</span>(</p><p>*args, **kwds)</p>
    </div>
    

    
  
    <div class="desc"><p>Convenience function to step in and out of a directory temporarily.</p></div>
  <div class="source_cont">
  <p class="source_link"><a href="javascript:void(0);" onclick="toggle('source-nimporter.cd', this);">Show source &equiv;</a></p>
  <div id="source-nimporter.cd" class="source">
    <div class="codehilite"><pre><span></span><span class="nd">@contextmanager</span>
<span class="k">def</span> <span class="nf">cd</span><span class="p">(</span><span class="n">path</span><span class="p">):</span>
    <span class="s2">&quot;Convenience function to step in and out of a directory temporarily.&quot;</span>
    <span class="n">cwd</span> <span class="o">=</span> <span class="n">os</span><span class="o">.</span><span class="n">getcwd</span><span class="p">()</span>
    <span class="n">os</span><span class="o">.</span><span class="n">chdir</span><span class="p">(</span><span class="n">path</span><span class="p">)</span>
    <span class="k">try</span><span class="p">:</span>
        <span class="k">yield</span> <span class="n">path</span>
    <span class="k">finally</span><span class="p">:</span>
        <span class="n">os</span><span class="o">.</span><span class="n">chdir</span><span class="p">(</span><span class="n">cwd</span><span class="p">)</span>
</pre></div>

  </div>
</div>

  </div>
  
      
  <div class="item">
    <div class="name def" id="nimporter.register_importer">
    <p>def <span class="ident">register_importer</span>(</p><p>list_position)</p>
    </div>
    

    
  
    <div class="desc"><p>Adds a given importer class to <code>sys.meta_path</code> at a given position.</p>
<p>NOTE: The position in <code>sys.meta_path</code> is extremely relevant.</p>
<p>Args:
    list_position(int): the index in <code>sys.meta_path</code> to place the importer.</p></div>
  <div class="source_cont">
  <p class="source_link"><a href="javascript:void(0);" onclick="toggle('source-nimporter.register_importer', this);">Show source &equiv;</a></p>
  <div id="source-nimporter.register_importer" class="source">
    <div class="codehilite"><pre><span></span><span class="k">def</span> <span class="nf">register_importer</span><span class="p">(</span><span class="n">list_position</span><span class="p">):</span>
    <span class="sd">&quot;&quot;&quot;</span>
<span class="sd">    Adds a given importer class to `sys.meta_path` at a given position.</span>

<span class="sd">    NOTE: The position in `sys.meta_path` is extremely relevant.</span>

<span class="sd">    Args:</span>
<span class="sd">        list_position(int): the index in `sys.meta_path` to place the importer.</span>
<span class="sd">    &quot;&quot;&quot;</span>
    <span class="k">def</span> <span class="nf">decorator</span><span class="p">(</span><span class="n">importer</span><span class="p">):</span>
        <span class="k">nonlocal</span> <span class="n">list_position</span>

        <span class="c1"># Make the list_position act like how a list is normally indexed</span>
        <span class="k">if</span> <span class="n">list_position</span> <span class="o">&lt;</span> <span class="mi">0</span><span class="p">:</span>
            <span class="n">list_position</span> <span class="o">=</span> <span class="nb">len</span><span class="p">(</span><span class="n">sys</span><span class="o">.</span><span class="n">meta_path</span><span class="p">)</span> <span class="o">+</span> <span class="mi">1</span> <span class="o">-</span> <span class="n">list_position</span>
 
        <span class="n">sys</span><span class="o">.</span><span class="n">meta_path</span><span class="o">.</span><span class="n">insert</span><span class="p">(</span><span class="n">list_position</span><span class="p">,</span> <span class="n">importer</span><span class="p">)</span>

        <span class="c1"># Ensure that Nim files won&#39;t be passed up because of other Importers.</span>
        <span class="n">sys</span><span class="o">.</span><span class="n">path_importer_cache</span><span class="o">.</span><span class="n">clear</span><span class="p">()</span>
        <span class="n">importlib</span><span class="o">.</span><span class="n">invalidate_caches</span><span class="p">()</span>

        <span class="k">return</span> <span class="n">importer</span>
    <span class="k">return</span> <span class="n">decorator</span>
</pre></div>

  </div>
</div>

  </div>
  

    <h2 class="section-title" id="header-classes">Classes</h2>
      
      <div class="item">
      <p id="nimporter.NimCompileException" class="name">class <span class="ident">NimCompileException</span></p>
      
  
    <div class="desc"><p>Indicates that the invocation of the Nim compiler has failed.
Displays the line of code that caused the error as well as the error message
returned from Nim as a Python Exception.</p>
<p>NOTE: The provided message must contain the string: 'Error:'</p></div>
  <div class="source_cont">
  <p class="source_link"><a href="javascript:void(0);" onclick="toggle('source-nimporter.NimCompileException', this);">Show source &equiv;</a></p>
  <div id="source-nimporter.NimCompileException" class="source">
    <div class="codehilite"><pre><span></span><span class="k">class</span> <span class="nc">NimCompileException</span><span class="p">(</span><span class="n">NimporterException</span><span class="p">):</span>
    <span class="sd">&quot;&quot;&quot;</span>
<span class="sd">    Indicates that the invocation of the Nim compiler has failed.</span>
<span class="sd">    Displays the line of code that caused the error as well as the error message</span>
<span class="sd">    returned from Nim as a Python Exception.</span>

<span class="sd">    NOTE: The provided message must contain the string: &#39;Error:&#39;</span>
<span class="sd">    &quot;&quot;&quot;</span>
    <span class="k">def</span> <span class="fm">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">msg</span><span class="p">):</span>
        <span class="k">if</span> <span class="n">sys</span><span class="o">.</span><span class="n">platform</span> <span class="o">==</span> <span class="s1">&#39;win32&#39;</span> <span class="ow">and</span> <span class="s1">&#39;external&#39;</span> <span class="ow">in</span> <span class="n">msg</span><span class="p">:</span>
            <span class="bp">self</span><span class="o">.</span><span class="n">message</span> <span class="o">=</span> <span class="n">msg</span>

        <span class="k">else</span><span class="p">:</span>
            <span class="n">nim_module</span><span class="p">,</span> <span class="n">error_msg</span> <span class="o">=</span> <span class="n">msg</span><span class="o">.</span><span class="n">split</span><span class="p">(</span><span class="s1">&#39;Error:&#39;</span><span class="p">)</span>
            <span class="n">nim_module</span> <span class="o">=</span> <span class="n">nim_module</span><span class="o">.</span><span class="n">splitlines</span><span class="p">()[</span><span class="o">-</span><span class="mi">1</span><span class="p">]</span>
            <span class="n">mod</span><span class="p">,</span> <span class="p">(</span><span class="n">line_col</span><span class="p">)</span> <span class="o">=</span> <span class="n">nim_module</span><span class="o">.</span><span class="n">split</span><span class="p">(</span><span class="s1">&#39;(&#39;</span><span class="p">)</span>
            <span class="n">nim_module</span> <span class="o">=</span> <span class="n">Path</span><span class="p">(</span><span class="n">mod</span><span class="p">)</span>
            <span class="n">line</span><span class="p">,</span> <span class="n">col</span> <span class="o">=</span> <span class="n">line_col</span><span class="o">.</span><span class="n">split</span><span class="p">(</span><span class="s1">&#39;,&#39;</span><span class="p">)</span>
            <span class="n">line</span> <span class="o">=</span> <span class="nb">int</span><span class="p">(</span><span class="n">line</span><span class="p">)</span>
            <span class="n">col</span> <span class="o">=</span> <span class="nb">int</span><span class="p">(</span><span class="n">col</span><span class="o">.</span><span class="n">replace</span><span class="p">(</span><span class="s1">&#39;)&#39;</span><span class="p">,</span> <span class="s1">&#39;&#39;</span><span class="p">))</span>
            <span class="n">message</span> <span class="o">=</span> <span class="n">error_msg</span> <span class="o">+</span> <span class="s1">&#39;</span><span class="se">\n</span><span class="s1">&#39;</span>
            
            <span class="k">with</span> <span class="nb">open</span><span class="p">(</span><span class="n">nim_module</span><span class="p">,</span> <span class="s1">&#39;r&#39;</span><span class="p">)</span> <span class="k">as</span> <span class="n">mod</span><span class="p">:</span>
                <span class="n">line</span> <span class="o">=</span> <span class="mi">0</span>
                <span class="k">for</span> <span class="n">each_line</span> <span class="ow">in</span> <span class="n">mod</span><span class="p">:</span>
                    <span class="n">line</span> <span class="o">+=</span> <span class="mi">1</span>

                    <span class="k">if</span> <span class="n">line</span> <span class="o">==</span> <span class="n">line</span><span class="p">:</span>
                        <span class="n">message</span> <span class="o">+=</span> <span class="sa">f</span><span class="s1">&#39; -&gt; </span><span class="si">{each_line}</span><span class="s1">&#39;</span>
                        
                    <span class="k">elif</span> <span class="n">line</span> <span class="o">&gt;</span> <span class="n">line</span> <span class="o">+</span> <span class="mi">2</span><span class="p">:</span>
                        <span class="k">break</span>
                    
                    <span class="k">elif</span> <span class="n">line</span> <span class="o">&gt;</span> <span class="n">line</span> <span class="o">-</span> <span class="mi">3</span><span class="p">:</span>
                        <span class="n">message</span> <span class="o">+=</span> <span class="sa">f</span><span class="s1">&#39; |  </span><span class="si">{each_line}</span><span class="s1">&#39;</span>

            <span class="bp">self</span><span class="o">.</span><span class="n">message</span> <span class="o">=</span> <span class="n">message</span><span class="o">.</span><span class="n">rstrip</span><span class="p">()</span> <span class="o">+</span> <span class="p">(</span>
                <span class="sa">f</span><span class="s1">&#39;</span><span class="se">\n\n</span><span class="s1">At {nim_module.absolute()} &#39;</span>
                <span class="sa">f</span><span class="s1">&#39;</span><span class="si">{line}</span><span class="s1">:</span><span class="si">{col}</span><span class="s1">&#39;</span>
            <span class="p">)</span>
        
    <span class="k">def</span> <span class="fm">__str__</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
        <span class="s2">&quot;Return the string representation of the given compiler error.&quot;</span>
        <span class="k">return</span> <span class="bp">self</span><span class="o">.</span><span class="n">message</span>
</pre></div>

  </div>
</div>


      <div class="class">
          <h3>Ancestors (in MRO)</h3>
          <ul class="class_list">
          <li><a href="#nimporter.NimCompileException">NimCompileException</a></li>
          <li><a href="#nimporter.NimporterException">NimporterException</a></li>
          <li>builtins.Exception</li>
          <li>builtins.BaseException</li>
          <li>builtins.object</li>
          </ul>
          <h3>Class variables</h3>
            <div class="item">
            <p id="nimporter.NimCompileException.args" class="name">var <span class="ident">args</span></p>
            

            
  
  <div class="source_cont">
</div>

            </div>
          <h3>Static methods</h3>
            
  <div class="item">
    <div class="name def" id="nimporter.NimCompileException.__init__">
    <p>def <span class="ident">__init__</span>(</p><p>self, msg)</p>
    </div>
    

    
  
    <div class="desc"><p>Initialize self.  See help(type(self)) for accurate signature.</p></div>
  <div class="source_cont">
  <p class="source_link"><a href="javascript:void(0);" onclick="toggle('source-nimporter.NimCompileException.__init__', this);">Show source &equiv;</a></p>
  <div id="source-nimporter.NimCompileException.__init__" class="source">
    <div class="codehilite"><pre><span></span><span class="k">def</span> <span class="fm">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">msg</span><span class="p">):</span>
    <span class="k">if</span> <span class="n">sys</span><span class="o">.</span><span class="n">platform</span> <span class="o">==</span> <span class="s1">&#39;win32&#39;</span> <span class="ow">and</span> <span class="s1">&#39;external&#39;</span> <span class="ow">in</span> <span class="n">msg</span><span class="p">:</span>
        <span class="bp">self</span><span class="o">.</span><span class="n">message</span> <span class="o">=</span> <span class="n">msg</span>
    <span class="k">else</span><span class="p">:</span>
        <span class="n">nim_module</span><span class="p">,</span> <span class="n">error_msg</span> <span class="o">=</span> <span class="n">msg</span><span class="o">.</span><span class="n">split</span><span class="p">(</span><span class="s1">&#39;Error:&#39;</span><span class="p">)</span>
        <span class="n">nim_module</span> <span class="o">=</span> <span class="n">nim_module</span><span class="o">.</span><span class="n">splitlines</span><span class="p">()[</span><span class="o">-</span><span class="mi">1</span><span class="p">]</span>
        <span class="n">mod</span><span class="p">,</span> <span class="p">(</span><span class="n">line_col</span><span class="p">)</span> <span class="o">=</span> <span class="n">nim_module</span><span class="o">.</span><span class="n">split</span><span class="p">(</span><span class="s1">&#39;(&#39;</span><span class="p">)</span>
        <span class="n">nim_module</span> <span class="o">=</span> <span class="n">Path</span><span class="p">(</span><span class="n">mod</span><span class="p">)</span>
        <span class="n">line</span><span class="p">,</span> <span class="n">col</span> <span class="o">=</span> <span class="n">line_col</span><span class="o">.</span><span class="n">split</span><span class="p">(</span><span class="s1">&#39;,&#39;</span><span class="p">)</span>
        <span class="n">line</span> <span class="o">=</span> <span class="nb">int</span><span class="p">(</span><span class="n">line</span><span class="p">)</span>
        <span class="n">col</span> <span class="o">=</span> <span class="nb">int</span><span class="p">(</span><span class="n">col</span><span class="o">.</span><span class="n">replace</span><span class="p">(</span><span class="s1">&#39;)&#39;</span><span class="p">,</span> <span class="s1">&#39;&#39;</span><span class="p">))</span>
        <span class="n">message</span> <span class="o">=</span> <span class="n">error_msg</span> <span class="o">+</span> <span class="s1">&#39;</span><span class="se">\n</span><span class="s1">&#39;</span>
        
        <span class="k">with</span> <span class="nb">open</span><span class="p">(</span><span class="n">nim_module</span><span class="p">,</span> <span class="s1">&#39;r&#39;</span><span class="p">)</span> <span class="k">as</span> <span class="n">mod</span><span class="p">:</span>
            <span class="n">line</span> <span class="o">=</span> <span class="mi">0</span>
            <span class="k">for</span> <span class="n">each_line</span> <span class="ow">in</span> <span class="n">mod</span><span class="p">:</span>
                <span class="n">line</span> <span class="o">+=</span> <span class="mi">1</span>
                <span class="k">if</span> <span class="n">line</span> <span class="o">==</span> <span class="n">line</span><span class="p">:</span>
                    <span class="n">message</span> <span class="o">+=</span> <span class="sa">f</span><span class="s1">&#39; -&gt; </span><span class="si">{each_line}</span><span class="s1">&#39;</span>
                    
                <span class="k">elif</span> <span class="n">line</span> <span class="o">&gt;</span> <span class="n">line</span> <span class="o">+</span> <span class="mi">2</span><span class="p">:</span>
                    <span class="k">break</span>
                
                <span class="k">elif</span> <span class="n">line</span> <span class="o">&gt;</span> <span class="n">line</span> <span class="o">-</span> <span class="mi">3</span><span class="p">:</span>
                    <span class="n">message</span> <span class="o">+=</span> <span class="sa">f</span><span class="s1">&#39; |  </span><span class="si">{each_line}</span><span class="s1">&#39;</span>
        <span class="bp">self</span><span class="o">.</span><span class="n">message</span> <span class="o">=</span> <span class="n">message</span><span class="o">.</span><span class="n">rstrip</span><span class="p">()</span> <span class="o">+</span> <span class="p">(</span>
            <span class="sa">f</span><span class="s1">&#39;</span><span class="se">\n\n</span><span class="s1">At {nim_module.absolute()} &#39;</span>
            <span class="sa">f</span><span class="s1">&#39;</span><span class="si">{line}</span><span class="s1">:</span><span class="si">{col}</span><span class="s1">&#39;</span>
        <span class="p">)</span>
</pre></div>

  </div>
</div>

  </div>
  
      </div>
      </div>
      
      <div class="item">
      <p id="nimporter.NimCompiler" class="name">class <span class="ident">NimCompiler</span></p>
      
  
    <div class="desc"><p>Nim compiler invoker. Features:
 - Compile Nim files and return any failure messages as Python exceptions.
 - Store hashes of Nim source files to only recompile when module changes.
 - Stores hash in <strong>pycache</strong> directory to not clutter up file system.
 - Compile Nim files to C and bundle them as an Extension for distribution.</p>
<p>Attributes:
    EXT(str): the extension to use for the importable build artifact.
    NIM_CLI_ARGS(list): compiler switches common to all builds.</p></div>
  <div class="source_cont">
  <p class="source_link"><a href="javascript:void(0);" onclick="toggle('source-nimporter.NimCompiler', this);">Show source &equiv;</a></p>
  <div id="source-nimporter.NimCompiler" class="source">
    <div class="codehilite"><pre><span></span><span class="k">class</span> <span class="nc">NimCompiler</span><span class="p">:</span>
    <span class="sd">&quot;&quot;&quot;</span>
<span class="sd">    Nim compiler invoker. Features:</span>
<span class="sd">     - Compile Nim files and return any failure messages as Python exceptions.</span>
<span class="sd">     - Store hashes of Nim source files to only recompile when module changes.</span>
<span class="sd">     - Stores hash in __pycache__ directory to not clutter up file system.</span>
<span class="sd">     - Compile Nim files to C and bundle them as an Extension for distribution.</span>
<span class="sd">    </span>
<span class="sd">    Attributes:</span>
<span class="sd">        EXT(str): the extension to use for the importable build artifact.</span>
<span class="sd">        NIM_CLI_ARGS(list): compiler switches common to all builds.</span>
<span class="sd">    &quot;&quot;&quot;</span>
    <span class="n">EXT</span> <span class="o">=</span> <span class="s1">&#39;.pyd&#39;</span> <span class="k">if</span> <span class="n">sys</span><span class="o">.</span><span class="n">platform</span> <span class="o">==</span> <span class="s1">&#39;win32&#39;</span> <span class="k">else</span> <span class="s1">&#39;.so&#39;</span>
    <span class="n">NIM_CLI_ARGS</span> <span class="o">=</span> <span class="p">[</span>
        <span class="s1">&#39;--opt:speed&#39;</span><span class="p">,</span>
        <span class="s1">&#39;--parallelBuild:0&#39;</span><span class="p">,</span>
        <span class="s1">&#39;--gc:markAndSweep&#39;</span><span class="p">,</span>
        <span class="s1">&#39;--threads:on&#39;</span><span class="p">,</span>
        <span class="s1">&#39;--app:lib&#39;</span><span class="p">,</span>
        <span class="s1">&#39;-d:release&#39;</span><span class="p">,</span>
        <span class="s1">&#39;-d:ssl&#39;</span>
    <span class="p">]</span> <span class="o">+</span> <span class="p">([</span><span class="s1">&#39;--cc:vcc&#39;</span><span class="p">]</span> <span class="k">if</span> <span class="n">sys</span><span class="o">.</span><span class="n">platform</span> <span class="o">==</span> <span class="s1">&#39;win32&#39;</span> <span class="k">else</span> <span class="p">[])</span>
    <span class="n">EXT_DIR</span> <span class="o">=</span> <span class="s1">&#39;nim-extensions&#39;</span>

    <span class="nd">@classmethod</span>
    <span class="k">def</span> <span class="nf">build_artifact</span><span class="p">(</span><span class="bp">cls</span><span class="p">,</span> <span class="n">module_path</span><span class="p">):</span>
        <span class="sd">&quot;&quot;&quot;</span>
<span class="sd">        Returns the Path to the built .PYD or .SO. Does not imply it has already</span>
<span class="sd">        been built.</span>

<span class="sd">        Args:</span>
<span class="sd">            module_path(Path): the path to the module or library.</span>

<span class="sd">        Returns:</span>
<span class="sd">            The path to a build artifact if compilation were to succeed. If the</span>
<span class="sd">            module_path is a directory, an appropriate build artifact path</span>
<span class="sd">            within that directory is returned.</span>
<span class="sd">        &quot;&quot;&quot;</span>
        <span class="n">filename</span> <span class="o">=</span> <span class="n">module_path</span><span class="o">.</span><span class="n">stem</span> <span class="o">+</span> <span class="bp">cls</span><span class="o">.</span><span class="n">EXT</span>
        <span class="k">return</span> <span class="p">(</span><span class="bp">cls</span><span class="o">.</span><span class="n">pycache_dir</span><span class="p">(</span><span class="n">module_path</span><span class="p">)</span> <span class="o">/</span> <span class="n">filename</span><span class="p">)</span><span class="o">.</span><span class="n">resolve</span><span class="p">()</span>

    <span class="nd">@classmethod</span>
    <span class="k">def</span> <span class="nf">pycache_dir</span><span class="p">(</span><span class="bp">cls</span><span class="p">,</span> <span class="n">module_path</span><span class="p">):</span>
        <span class="sd">&quot;&quot;&quot;</span>
<span class="sd">        Return the `__pycache__` directory as a Path.</span>

<span class="sd">        Works the same as Python&#39;s `__pycache__` directory except now it works</span>
<span class="sd">        with Nim extensions also. It works literally exactly like Python.</span>

<span class="sd">        Args:</span>
<span class="sd">            module_path(Path): the path to a given Nim module or library.</span>

<span class="sd">        Returns:</span>
<span class="sd">            The Path to the `__pycache__` directory that the build artifact</span>
<span class="sd">            should be stored.</span>
<span class="sd">        &quot;&quot;&quot;</span>
        <span class="k">if</span> <span class="n">module_path</span><span class="o">.</span><span class="n">is_dir</span><span class="p">():</span>
            <span class="k">return</span> <span class="p">(</span><span class="n">module_path</span> <span class="o">/</span> <span class="s1">&#39;__pycache__&#39;</span><span class="p">)</span><span class="o">.</span><span class="n">resolve</span><span class="p">()</span>
        <span class="k">else</span><span class="p">:</span>
            <span class="k">return</span> <span class="p">(</span><span class="n">module_path</span><span class="o">.</span><span class="n">parent</span> <span class="o">/</span> <span class="s1">&#39;__pycache__&#39;</span><span class="p">)</span><span class="o">.</span><span class="n">resolve</span><span class="p">()</span>

    <span class="nd">@classmethod</span>
    <span class="k">def</span> <span class="nf">invoke_compiler</span><span class="p">(</span><span class="bp">cls</span><span class="p">,</span> <span class="n">nim_args</span><span class="p">:</span> <span class="nb">list</span><span class="p">):</span>
        <span class="sd">&quot;&quot;&quot;</span>
<span class="sd">        Invokes the compiler (or any executable) and returns the output.</span>

<span class="sd">        While this can (and has been) used to call executables other than Nim</span>
<span class="sd">        and Nimble, it should be noted that the warnings and hints are artifacts</span>
<span class="sd">        of being mainly targeted as a Nim compiler invoker.</span>

<span class="sd">        Args:</span>
<span class="sd">            nim_args(list): the arg being the executable and the rest are args.</span>

<span class="sd">        Returns:</span>
<span class="sd">            A tuple containing any errors, warnings, or hints from the</span>
<span class="sd">            compilation process.</span>
<span class="sd">        &quot;&quot;&quot;</span>
        <span class="n">process</span> <span class="o">=</span> <span class="n">subprocess</span><span class="o">.</span><span class="n">run</span><span class="p">(</span>
            <span class="n">nim_args</span><span class="p">,</span> <span class="n">stdout</span><span class="o">=</span><span class="n">subprocess</span><span class="o">.</span><span class="n">PIPE</span><span class="p">,</span> <span class="n">stderr</span><span class="o">=</span><span class="n">subprocess</span><span class="o">.</span><span class="n">PIPE</span>
        <span class="p">)</span>
        <span class="n">out</span><span class="p">,</span> <span class="n">err</span> <span class="o">=</span> <span class="n">process</span><span class="o">.</span><span class="n">stdout</span><span class="p">,</span> <span class="n">process</span><span class="o">.</span><span class="n">stderr</span>
        <span class="n">out</span> <span class="o">=</span> <span class="n">out</span><span class="o">.</span><span class="n">decode</span><span class="p">()</span> <span class="k">if</span> <span class="n">out</span> <span class="k">else</span> <span class="s1">&#39;&#39;</span>
        <span class="n">err</span> <span class="o">=</span> <span class="n">err</span><span class="o">.</span><span class="n">decode</span><span class="p">()</span> <span class="k">if</span> <span class="n">err</span> <span class="k">else</span> <span class="s1">&#39;&#39;</span>
        <span class="n">lines</span> <span class="o">=</span> <span class="p">(</span><span class="n">out</span> <span class="o">+</span> <span class="n">err</span><span class="p">)</span><span class="o">.</span><span class="n">splitlines</span><span class="p">()</span>

        <span class="n">errors</span>   <span class="o">=</span> <span class="p">[</span><span class="n">line</span> <span class="k">for</span> <span class="n">line</span> <span class="ow">in</span> <span class="n">lines</span> <span class="k">if</span> <span class="s1">&#39;Error:&#39;</span> <span class="ow">in</span> <span class="n">line</span><span class="p">]</span>
        <span class="n">warnings</span> <span class="o">=</span> <span class="p">[</span><span class="n">line</span> <span class="k">for</span> <span class="n">line</span> <span class="ow">in</span> <span class="n">lines</span> <span class="k">if</span> <span class="s1">&#39;Warning:&#39;</span> <span class="ow">in</span> <span class="n">line</span><span class="p">]</span>
        <span class="n">hints</span>    <span class="o">=</span> <span class="p">[</span><span class="n">line</span> <span class="k">for</span> <span class="n">line</span> <span class="ow">in</span> <span class="n">lines</span> <span class="k">if</span> <span class="s1">&#39;Hint:&#39;</span> <span class="ow">in</span> <span class="n">line</span><span class="p">]</span>

        <span class="k">return</span> <span class="n">out</span><span class="p">,</span> <span class="n">errors</span><span class="p">,</span> <span class="n">warnings</span><span class="p">,</span> <span class="n">hints</span>

    <span class="nd">@classmethod</span>
    <span class="k">def</span> <span class="nf">ensure_nimpy</span><span class="p">(</span><span class="bp">cls</span><span class="p">):</span>
        <span class="sd">&quot;&quot;&quot;</span>
<span class="sd">        Makes sure that the Nimpy Nim library is installed.</span>

<span class="sd">        Verifies that the [Nimpy Library](https://github.com/yglukhov/nimpy) is</span>
<span class="sd">        installed and installs it otherwise.</span>

<span class="sd">        NOTE: Nimporter would not be possible without Nimpy. Thank you</span>
<span class="sd">        Yuriy Glukhov for making this project possible!</span>
<span class="sd">        &quot;&quot;&quot;</span>
        <span class="n">out</span><span class="p">,</span> <span class="n">errors</span><span class="p">,</span> <span class="n">_</span><span class="p">,</span> <span class="n">_</span> <span class="o">=</span> <span class="bp">cls</span><span class="o">.</span><span class="n">invoke_compiler</span><span class="p">(</span><span class="s1">&#39;nimble path nimpy&#39;</span><span class="o">.</span><span class="n">split</span><span class="p">())</span>

        <span class="k">if</span> <span class="ow">not</span> <span class="n">out</span> <span class="ow">or</span> <span class="n">errors</span><span class="p">:</span>
            <span class="n">nimble_args</span> <span class="o">=</span> <span class="s1">&#39;nimble install nimpy --accept&#39;</span><span class="o">.</span><span class="n">split</span><span class="p">()</span>
            <span class="n">out</span><span class="p">,</span> <span class="n">errors</span><span class="p">,</span> <span class="n">_</span><span class="p">,</span> <span class="n">_</span> <span class="o">=</span> <span class="bp">cls</span><span class="o">.</span><span class="n">invoke_compiler</span><span class="p">(</span><span class="n">nimble_args</span><span class="p">)</span>

        <span class="k">if</span> <span class="n">errors</span><span class="p">:</span> <span class="k">raise</span> <span class="n">NimInvokeException</span><span class="p">(</span><span class="n">Path</span><span class="p">(),</span> <span class="n">nimble_args</span><span class="p">,</span> <span class="n">errors</span><span class="p">,</span> <span class="n">out</span><span class="p">)</span>

    <span class="nd">@staticmethod</span>
    <span class="k">def</span> <span class="nf">get_import_prefix</span><span class="p">(</span><span class="n">module_path</span><span class="p">,</span> <span class="n">root</span><span class="p">):</span>
        <span class="sd">&quot;&quot;&quot;</span>
<span class="sd">        Computes the proper name of a Nim module amid a given Python project.</span>

<span class="sd">        This method is needed because Nim Extensions do not automatically know</span>
<span class="sd">        where they are within a given Python namespace. This method is vital for</span>
<span class="sd">        recursing through an entire Python project to find every Nim Extension</span>
<span class="sd">        module and library while preserving the namespace containing each one.</span>

<span class="sd">        Args:</span>
<span class="sd">            module_path(Path): the module for which to determine its namespace.</span>
<span class="sd">            root(Path): the path to the Python project containing the Extension.</span>

<span class="sd">        Returns:</span>
<span class="sd">            A tuple of packages containing the given module.</span>
<span class="sd">        &quot;&quot;&quot;</span>
        <span class="n">root_path</span> <span class="o">=</span> <span class="n">root</span><span class="o">.</span><span class="n">resolve</span><span class="p">()</span>
        <span class="n">full_path</span> <span class="o">=</span> <span class="n">module_path</span><span class="o">.</span><span class="n">resolve</span><span class="p">()</span>

        <span class="k">assert</span> <span class="n">full_path</span> <span class="o">&gt;=</span> <span class="n">root_path</span><span class="p">,</span> <span class="s1">&#39;Extension path is not within root dir.&#39;</span>

        <span class="k">return</span> <span class="n">full_path</span><span class="o">.</span><span class="n">parts</span><span class="p">[</span><span class="nb">len</span><span class="p">(</span><span class="n">root_path</span><span class="o">.</span><span class="n">parts</span><span class="p">):]</span>

    <span class="nd">@classmethod</span>
    <span class="k">def</span> <span class="nf">find_nim_std_lib</span><span class="p">(</span><span class="bp">cls</span><span class="p">):</span>
        <span class="sd">&quot;&quot;&quot;</span>
<span class="sd">        Finds the path to the `lib/` directory within a given Nim installation.</span>

<span class="sd">        Has the ability to find Nim&#39;s stdlib on Windows, MacOS, and Linux. Can</span>
<span class="sd">        also find the stdlib when Nim was installed via Choosenim. Additionally,</span>
<span class="sd">        it can even find the stdlib of the currently selected toolchain when</span>
<span class="sd">        using Choosenim.</span>

<span class="sd">        Returns:</span>
<span class="sd">            The Path to the Nim stdlib &#39;lib&#39; directory if it exists and None</span>
<span class="sd">            otherwise.</span>
<span class="sd">        &quot;&quot;&quot;</span>

        <span class="c1"># Installed via ChooseNim</span>
        <span class="k">if</span> <span class="n">shutil</span><span class="o">.</span><span class="n">which</span><span class="p">(</span><span class="s1">&#39;choosenim&#39;</span><span class="p">):</span>
            <span class="n">o</span><span class="p">,</span> <span class="n">_</span><span class="p">,</span> <span class="n">_</span><span class="p">,</span> <span class="n">_</span> <span class="o">=</span> <span class="bp">cls</span><span class="o">.</span><span class="n">invoke_compiler</span><span class="p">(</span>
                <span class="s1">&#39;choosenim show -y --nocolor&#39;</span><span class="o">.</span><span class="n">split</span><span class="p">()</span>
            <span class="p">)</span>
            <span class="p">(</span><span class="n">choosenim</span><span class="p">,)</span> <span class="o">=</span> <span class="p">[</span><span class="n">i</span> <span class="k">for</span> <span class="n">i</span> <span class="ow">in</span> <span class="n">o</span><span class="o">.</span><span class="n">splitlines</span><span class="p">()</span> <span class="k">if</span> <span class="s1">&#39;Path:&#39;</span> <span class="ow">in</span> <span class="n">i</span><span class="p">]</span>
            <span class="n">toolchain</span> <span class="o">=</span> <span class="n">Path</span><span class="p">(</span><span class="n">choosenim</span><span class="o">.</span><span class="n">split</span><span class="p">(</span><span class="s1">&#39;Path:&#39;</span><span class="p">)</span><span class="o">.</span><span class="n">pop</span><span class="p">()</span><span class="o">.</span><span class="n">strip</span><span class="p">())</span>
            <span class="n">stdlib</span> <span class="o">=</span> <span class="n">toolchain</span> <span class="o">/</span> <span class="s1">&#39;lib&#39;</span>
            <span class="k">if</span> <span class="ow">not</span> <span class="p">(</span><span class="n">stdlib</span> <span class="o">/</span> <span class="s1">&#39;system.nim&#39;</span><span class="p">)</span><span class="o">.</span><span class="n">exists</span><span class="p">():</span>
                <span class="k">return</span> <span class="kc">None</span>
            <span class="k">return</span> <span class="n">stdlib</span><span class="o">.</span><span class="n">resolve</span><span class="p">()</span><span class="o">.</span><span class="n">absolute</span><span class="p">()</span>

        <span class="c1"># Installed manually</span>
        <span class="n">nimexe</span> <span class="o">=</span> <span class="n">shutil</span><span class="o">.</span><span class="n">which</span><span class="p">(</span><span class="s1">&#39;nim&#39;</span><span class="p">)</span>
        <span class="k">if</span> <span class="ow">not</span> <span class="n">nimexe</span><span class="p">:</span>
            <span class="k">return</span> <span class="kc">None</span>
        <span class="n">nimexe</span> <span class="o">=</span> <span class="n">Path</span><span class="p">(</span><span class="n">nimexe</span><span class="p">)</span>
        <span class="n">result</span> <span class="o">=</span> <span class="n">nimexe</span><span class="o">.</span><span class="n">parent</span> <span class="o">/</span> <span class="s1">&#39;../lib&#39;</span>
        <span class="k">if</span> <span class="ow">not</span> <span class="p">(</span><span class="n">result</span> <span class="o">/</span> <span class="s1">&#39;system.nim&#39;</span><span class="p">)</span><span class="o">.</span><span class="n">exists</span><span class="p">():</span>
            <span class="n">result</span> <span class="o">=</span> <span class="n">nimexe</span><span class="o">.</span><span class="n">resolve</span><span class="p">()</span><span class="o">.</span><span class="n">parent</span> <span class="o">/</span> <span class="s1">&#39;../lib&#39;</span>
            <span class="k">if</span> <span class="ow">not</span> <span class="p">(</span><span class="n">result</span> <span class="o">/</span> <span class="s1">&#39;system.nim&#39;</span><span class="p">)</span><span class="o">.</span><span class="n">exists</span><span class="p">():</span>
                <span class="k">return</span> <span class="kc">None</span>
        <span class="k">return</span> <span class="n">result</span><span class="o">.</span><span class="n">resolve</span><span class="p">()</span><span class="o">.</span><span class="n">absolute</span><span class="p">()</span>

    <span class="nd">@classmethod</span>
    <span class="k">def</span> <span class="nf">get_switches</span><span class="p">(</span><span class="bp">cls</span><span class="p">,</span> <span class="n">switch_file</span><span class="p">,</span> <span class="o">**</span><span class="n">global_scope</span><span class="p">):</span>
        <span class="sd">&quot;&quot;&quot;</span>
<span class="sd">        Convenience function to return the switches from a given switchfile.</span>

<span class="sd">        Works by exposing a global scope to the switch file and then evaluating</span>
<span class="sd">        it. The resulting variable: `__switches__` should have been defined</span>
<span class="sd">        within the script which should contain the keys: &quot;import&quot; and &quot;bundle&quot;.</span>

<span class="sd">        The &quot;import&quot; key should be a list of CLI args that should be passed to</span>
<span class="sd">        the Nim compiler when importing the given Nim library.</span>

<span class="sd">        The &quot;bundle&quot; key should be a list of CLI args that should be passed to</span>
<span class="sd">        the Nim compiler when creating an Extension object from the C sources.</span>

<span class="sd">        When evaluated, the switchfile can make use of a few global variables</span>
<span class="sd">        that allow it to make certain decisions regarding the outcome of the</span>
<span class="sd">        compilation:</span>

<span class="sd">         * **MODULE_PATH**: the path to the actual Nim source file to compile</span>
<span class="sd">         * **BUILD_ARTIFACT**: can be used when building a module</span>
<span class="sd">         * **BUILD_DIR**: can be used when building a library</span>
<span class="sd">         * **IS_LIBRARY**: used to determine if a library/module is being built.</span>

<span class="sd">        The reason for the switchfile being a Python script is that different</span>
<span class="sd">        platforms will require different compilation switches. The switchfile</span>
<span class="sd">        author can make use of `sys.platform` to query platform information.</span>

<span class="sd">        Returns:</span>
<span class="sd">            A dictionary containing the keys: &quot;import&quot; and &quot;bundle&quot;, signifying</span>
<span class="sd">            the CLI arguments used when importing and building an extension</span>
<span class="sd">            module respectively.</span>
<span class="sd">        &quot;&quot;&quot;</span>
        <span class="n">global_scope</span> <span class="o">=</span> <span class="n">global_scope</span><span class="o">.</span><span class="n">copy</span><span class="p">()</span>
        <span class="k">assert</span> <span class="n">switch_file</span><span class="o">.</span><span class="n">exists</span><span class="p">(),</span> <span class="p">(</span>
            <span class="s1">&#39;Cannot open nonexistent switch file: &#39;</span> <span class="o">+</span> <span class="nb">str</span><span class="p">(</span><span class="n">switch_file</span><span class="p">)</span>
        <span class="p">)</span>
        <span class="n">exec</span><span class="p">(</span><span class="n">switch_file</span><span class="o">.</span><span class="n">read_text</span><span class="p">(),</span> <span class="n">global_scope</span><span class="p">)</span>
        <span class="k">return</span> <span class="n">global_scope</span><span class="p">[</span><span class="s1">&#39;__switches__&#39;</span><span class="p">]</span>

    <span class="nd">@classmethod</span>
    <span class="k">def</span> <span class="nf">compile_nim_extension</span><span class="p">(</span><span class="bp">cls</span><span class="p">,</span> <span class="n">module_path</span><span class="p">,</span> <span class="n">root</span><span class="p">,</span> <span class="o">*</span><span class="p">,</span> <span class="n">library</span><span class="p">:</span> <span class="nb">bool</span><span class="p">):</span>
        <span class="sd">&quot;&quot;&quot;</span>
<span class="sd">        Compiles/returns an Extension and installs `.nimble` dependencies.</span>

<span class="sd">        Libraries MUST have a Nim file named &quot;&lt;library name&gt;.nim&quot; at the project</span>
<span class="sd">        root as well as a file ending with &quot;.nimble&quot;.</span>

<span class="sd">        NOTE: The library parameter signifies (albeit subtly) that the given Nim</span>
<span class="sd">        library has (can have) dependencies specified in a Nimble file.</span>

<span class="sd">        Args:</span>
<span class="sd">            module_path(Path): the path to the library directory or a Nim file.</span>
<span class="sd">            root(Path): the path to the directory containing the entire project.</span>
<span class="sd">            library(bool): hint as to how to treat the `module_path` parameter.</span>

<span class="sd">        Returns:</span>
<span class="sd">            An Extension upon successful compilation, else None.</span>

<span class="sd">        Raises:</span>
<span class="sd">            Exception if the library path does not contain the files listed</span>
<span class="sd">            above or any other compilation error.</span>
<span class="sd">        &quot;&quot;&quot;</span>

        <span class="k">if</span> <span class="ow">not</span> <span class="n">module_path</span><span class="o">.</span><span class="n">exists</span><span class="p">():</span>
            <span class="k">raise</span> <span class="n">NimporterException</span><span class="p">(</span>
                <span class="sa">f</span><span class="s1">&#39;{module_path.absolute()} does not exist.&#39;</span>
            <span class="p">)</span>

        <span class="n">module_name</span> <span class="o">=</span> <span class="n">module_path</span><span class="o">.</span><span class="n">stem</span>

        <span class="k">if</span> <span class="n">module_path</span><span class="o">.</span><span class="n">is_file</span><span class="p">():</span>
            <span class="n">library_path</span> <span class="o">=</span> <span class="n">module_path</span><span class="o">.</span><span class="n">parent</span><span class="o">.</span><span class="n">resolve</span><span class="p">()</span>
            
        <span class="k">elif</span> <span class="n">module_path</span><span class="o">.</span><span class="n">is_dir</span><span class="p">():</span>
            <span class="n">library_path</span> <span class="o">=</span> <span class="n">module_path</span><span class="o">.</span><span class="n">resolve</span><span class="p">()</span>
            <span class="n">module_path</span> <span class="o">=</span> <span class="n">library_path</span> <span class="o">/</span> <span class="p">(</span><span class="n">library_path</span><span class="o">.</span><span class="n">name</span> <span class="o">+</span> <span class="s1">&#39;.nim&#39;</span><span class="p">)</span>

        <span class="k">if</span> <span class="n">library</span> <span class="ow">and</span> <span class="ow">not</span> <span class="nb">any</span><span class="p">(</span><span class="n">library_path</span><span class="o">.</span><span class="n">glob</span><span class="p">(</span><span class="s1">&#39;*.nimble&#39;</span><span class="p">)):</span>
            <span class="k">raise</span> <span class="n">NimporterException</span><span class="p">(</span>
            <span class="sa">f</span><span class="s2">&quot;Library: </span><span class="si">{library_path}</span><span class="s2"> doesn&#39;t contain a .nimble file&quot;</span>
        <span class="p">)</span>

        <span class="bp">cls</span><span class="o">.</span><span class="n">ensure_nimpy</span><span class="p">()</span>

        <span class="c1"># Coerce proper import path using root path</span>
        <span class="n">import_prefix</span> <span class="o">=</span> <span class="bp">cls</span><span class="o">.</span><span class="n">get_import_prefix</span><span class="p">(</span><span class="n">module_path</span><span class="o">.</span><span class="n">parent</span><span class="p">,</span> <span class="n">root</span><span class="p">)</span>
        <span class="n">module_part</span> <span class="o">=</span> <span class="nb">tuple</span><span class="p">()</span> <span class="k">if</span> <span class="n">library</span> <span class="k">else</span> <span class="p">(</span><span class="n">module_name</span><span class="p">,)</span>
        <span class="n">import_path</span> <span class="o">=</span> <span class="s1">&#39;.&#39;</span><span class="o">.</span><span class="n">join</span><span class="p">(</span><span class="n">import_prefix</span> <span class="o">+</span> <span class="n">module_part</span><span class="p">)</span>

        <span class="c1"># Record results of build so it can be copied into source archive</span>
        <span class="n">extension_dir</span> <span class="o">=</span> <span class="n">root</span> <span class="o">/</span> <span class="bp">cls</span><span class="o">.</span><span class="n">EXT_DIR</span>
        <span class="n">extension_dir</span><span class="o">.</span><span class="n">mkdir</span><span class="p">(</span><span class="n">parents</span><span class="o">=</span><span class="kc">True</span><span class="p">,</span> <span class="n">exist_ok</span><span class="o">=</span><span class="kc">True</span><span class="p">)</span>
        <span class="n">build_dir</span> <span class="o">=</span> <span class="n">extension_dir</span><span class="o">.</span><span class="n">absolute</span><span class="p">()</span> <span class="o">/</span> <span class="n">import_path</span>
        <span class="n">build_dir</span><span class="o">.</span><span class="n">mkdir</span><span class="p">(</span><span class="n">exist_ok</span><span class="o">=</span><span class="kc">True</span><span class="p">)</span>
        <span class="n">build_dir_relative</span> <span class="o">=</span> <span class="n">extension_dir</span> <span class="o">/</span> <span class="n">import_path</span>

        <span class="c1"># Switches file found</span>
        <span class="n">switch_file</span> <span class="o">=</span> <span class="n">library_path</span> <span class="o">/</span> <span class="s1">&#39;switches.py&#39;</span>
        <span class="k">if</span> <span class="n">switch_file</span><span class="o">.</span><span class="n">exists</span><span class="p">():</span>
            <span class="n">switches</span> <span class="o">=</span> <span class="bp">cls</span><span class="o">.</span><span class="n">get_switches</span><span class="p">(</span>
                <span class="n">switch_file</span><span class="p">,</span>
                <span class="n">MODULE_PATH</span><span class="o">=</span><span class="n">module_path</span><span class="p">,</span>
                <span class="n">BUILD_DIR</span><span class="o">=</span><span class="n">build_dir</span><span class="p">,</span>
                <span class="c1"># Necessary for import/bundle compatibility</span>
                <span class="n">BUILD_ARTIFACT</span><span class="o">=</span><span class="kc">None</span><span class="p">,</span>
                <span class="n">IS_LIBRARY</span><span class="o">=</span><span class="n">library</span>
            <span class="p">)</span>
            <span class="n">nim_args</span> <span class="o">=</span> <span class="n">switches</span><span class="p">[</span><span class="s1">&#39;bundle&#39;</span><span class="p">]</span>

        <span class="c1"># Use standard switches</span>
        <span class="k">else</span><span class="p">:</span>
            <span class="n">exe</span> <span class="o">=</span> <span class="p">[</span><span class="s1">&#39;nimble&#39;</span> <span class="k">if</span> <span class="n">library</span> <span class="k">else</span> <span class="s1">&#39;nim&#39;</span><span class="p">,</span> <span class="s1">&#39;cc&#39;</span><span class="p">,</span> <span class="s1">&#39;-c&#39;</span><span class="p">]</span>
            <span class="n">nim_args</span> <span class="o">=</span> <span class="p">(</span>
                <span class="n">exe</span> <span class="o">+</span> <span class="bp">cls</span><span class="o">.</span><span class="n">NIM_CLI_ARGS</span> <span class="o">+</span>
                <span class="p">[</span><span class="sa">f</span><span class="s1">&#39;--nimcache:</span><span class="si">{build_dir}</span><span class="s1">&#39;</span><span class="p">,</span> <span class="sa">f</span><span class="s1">&#39;</span><span class="si">{module_path}</span><span class="s1">&#39;</span><span class="p">]</span> <span class="o">+</span>
                <span class="p">([</span><span class="s1">&#39;--accept&#39;</span><span class="p">]</span> <span class="k">if</span> <span class="n">library</span> <span class="k">else</span> <span class="p">[])</span>
            <span class="p">)</span>

        <span class="k">with</span> <span class="n">cd</span><span class="p">(</span><span class="n">library_path</span> <span class="k">if</span> <span class="n">library</span> <span class="k">else</span> <span class="n">Path</span><span class="p">(</span><span class="s1">&#39;.&#39;</span><span class="p">))</span> <span class="k">as</span> <span class="n">tmp_cwd</span><span class="p">:</span>
            <span class="n">output</span><span class="p">,</span> <span class="n">errors</span><span class="p">,</span> <span class="n">warnings</span><span class="p">,</span> <span class="n">hints</span> <span class="o">=</span> <span class="bp">cls</span><span class="o">.</span><span class="n">invoke_compiler</span><span class="p">(</span><span class="n">nim_args</span><span class="p">)</span>

        <span class="k">if</span> <span class="n">errors</span><span class="p">:</span>
            <span class="k">if</span> <span class="n">library</span><span class="p">:</span>
                <span class="k">raise</span> <span class="n">NimInvokeException</span><span class="p">(</span><span class="n">tmp_cwd</span><span class="p">,</span> <span class="n">nim_args</span><span class="p">,</span> <span class="n">errors</span><span class="p">,</span> <span class="n">output</span><span class="p">)</span>
            <span class="k">else</span><span class="p">:</span>
                <span class="k">raise</span> <span class="n">NimCompileException</span><span class="p">(</span><span class="n">errors</span><span class="p">[</span><span class="mi">0</span><span class="p">])</span>

        <span class="k">for</span> <span class="n">warn</span> <span class="ow">in</span> <span class="n">warnings</span><span class="p">:</span> <span class="nb">print</span><span class="p">(</span><span class="n">warn</span><span class="p">)</span>

        <span class="n">csources</span> <span class="o">=</span> <span class="p">[</span>
            <span class="nb">str</span><span class="p">(</span><span class="n">c</span><span class="p">)</span> <span class="k">for</span> <span class="n">c</span> <span class="ow">in</span> <span class="n">build_dir_relative</span><span class="o">.</span><span class="n">iterdir</span><span class="p">()</span> <span class="k">if</span> <span class="n">c</span><span class="o">.</span><span class="n">suffix</span> <span class="o">==</span> <span class="s1">&#39;.c&#39;</span>
        <span class="p">]</span>

        <span class="c1"># Copy over needed header(s)</span>
        <span class="n">NIMBASE</span> <span class="o">=</span> <span class="s1">&#39;nimbase.h&#39;</span>
        <span class="n">nimbase</span> <span class="o">=</span> <span class="bp">cls</span><span class="o">.</span><span class="n">find_nim_std_lib</span><span class="p">()</span> <span class="o">/</span> <span class="n">NIMBASE</span>
        <span class="n">nimbase_dest</span> <span class="o">=</span> <span class="nb">str</span><span class="p">(</span><span class="n">build_dir_relative</span> <span class="o">/</span> <span class="n">NIMBASE</span><span class="p">)</span>
        <span class="n">shutil</span><span class="o">.</span><span class="n">copyfile</span><span class="p">(</span><span class="nb">str</span><span class="p">(</span><span class="n">nimbase</span><span class="p">),</span> <span class="n">nimbase_dest</span><span class="p">)</span>

        <span class="c1"># Properly handle bundling headers into the source distribution</span>
        <span class="n">manifest</span> <span class="o">=</span> <span class="n">root</span> <span class="o">/</span> <span class="s1">&#39;MANIFEST.in&#39;</span>
        <span class="k">if</span> <span class="ow">not</span> <span class="n">manifest</span><span class="o">.</span><span class="n">exists</span><span class="p">():</span>
            <span class="n">manifest</span><span class="o">.</span><span class="n">write_text</span><span class="p">(</span><span class="s1">&#39;# NIMPORTER BUNDLE</span><span class="se">\n</span><span class="s1">&#39;</span><span class="p">)</span>

        <span class="k">with</span> <span class="n">manifest</span><span class="o">.</span><span class="n">open</span><span class="p">(</span><span class="s1">&#39;a&#39;</span><span class="p">)</span> <span class="k">as</span> <span class="n">file</span><span class="p">:</span>
            <span class="n">file</span><span class="o">.</span><span class="n">write</span><span class="p">(</span><span class="sa">f</span><span class="s1">&#39;include </span><span class="si">{nimbase_dest}</span><span class="se">\n</span><span class="s1">&#39;</span><span class="p">)</span>

        <span class="k">return</span> <span class="n">Extension</span><span class="p">(</span>
            <span class="n">name</span><span class="o">=</span><span class="n">import_path</span><span class="p">,</span>
            <span class="n">sources</span><span class="o">=</span><span class="n">csources</span><span class="p">,</span>
            <span class="n">include_dirs</span><span class="o">=</span><span class="p">[</span><span class="nb">str</span><span class="p">(</span><span class="n">build_dir</span><span class="p">)]</span>
        <span class="p">)</span>

    <span class="nd">@classmethod</span>
    <span class="k">def</span> <span class="nf">compile_nim_code</span><span class="p">(</span><span class="bp">cls</span><span class="p">,</span> <span class="n">module_path</span><span class="p">,</span> <span class="n">build_artifact</span><span class="p">,</span> <span class="o">*</span><span class="p">,</span> <span class="n">library</span><span class="p">:</span> <span class="nb">bool</span><span class="p">):</span>
        <span class="sd">&quot;&quot;&quot;</span>
<span class="sd">        Returns a Spec object so a Nim module/library can be directly imported.</span>

<span class="sd">        NOTE: The `module_path` keyword argument can be either a path to a Nim</span>
<span class="sd">        file (in the case of `library=False`) or a path to a directory (in the</span>
<span class="sd">        case of `library=True`). However, it has a third supported usage. It can</span>
<span class="sd">        be a Nim module when `library=True` and this method will search for the</span>
<span class="sd">        Nimble file alongside the given path.</span>

<span class="sd">        NOTE: The library parameter signifies (albeit subtly) that the given Nim</span>
<span class="sd">        library has (can have) dependencies specified in a Nimble file.</span>
<span class="sd">        &quot;&quot;&quot;</span>

        <span class="k">if</span> <span class="ow">not</span> <span class="n">module_path</span><span class="o">.</span><span class="n">exists</span><span class="p">():</span>
            <span class="k">raise</span> <span class="n">NimporterException</span><span class="p">(</span>
                <span class="sa">f</span><span class="s1">&#39;{module_path.absolute()} does not exist.&#39;</span>
            <span class="p">)</span>

        <span class="k">if</span> <span class="n">library</span> <span class="ow">and</span> <span class="n">module_path</span><span class="o">.</span><span class="n">is_file</span><span class="p">():</span>
            <span class="k">raise</span> <span class="n">NimporterException</span><span class="p">(</span>
                <span class="s1">&#39;Librarys are built using folder name, not specific Nim module&#39;</span>
            <span class="p">)</span>

        <span class="k">elif</span> <span class="ow">not</span> <span class="n">library</span> <span class="ow">and</span> <span class="n">module_path</span><span class="o">.</span><span class="n">is_dir</span><span class="p">():</span>
            <span class="k">raise</span> <span class="n">NimporterException</span><span class="p">(</span>
                <span class="s1">&#39;Modules are built using module name, not containing folder&#39;</span>
            <span class="p">)</span>

        <span class="k">if</span> <span class="n">module_path</span><span class="o">.</span><span class="n">is_file</span><span class="p">():</span>
            <span class="n">library_path</span> <span class="o">=</span> <span class="n">module_path</span><span class="o">.</span><span class="n">parent</span><span class="o">.</span><span class="n">resolve</span><span class="p">()</span>

        <span class="k">elif</span> <span class="n">module_path</span><span class="o">.</span><span class="n">is_dir</span><span class="p">():</span>
            <span class="n">library_path</span> <span class="o">=</span> <span class="n">module_path</span><span class="o">.</span><span class="n">resolve</span><span class="p">()</span>
            <span class="n">module_path</span> <span class="o">=</span> <span class="n">library_path</span> <span class="o">/</span> <span class="p">(</span><span class="n">library_path</span><span class="o">.</span><span class="n">name</span> <span class="o">+</span> <span class="s1">&#39;.nim&#39;</span><span class="p">)</span>

        <span class="k">if</span> <span class="n">library</span> <span class="ow">and</span> <span class="ow">not</span> <span class="nb">any</span><span class="p">(</span><span class="n">library_path</span><span class="o">.</span><span class="n">glob</span><span class="p">(</span><span class="s1">&#39;*.nimble&#39;</span><span class="p">)):</span>
            <span class="k">raise</span> <span class="n">NimporterException</span><span class="p">(</span>
            <span class="sa">f</span><span class="s2">&quot;Library: </span><span class="si">{library_path}</span><span class="s2"> doesn&#39;t contain a .nimble file&quot;</span>
        <span class="p">)</span>

        <span class="bp">cls</span><span class="o">.</span><span class="n">ensure_nimpy</span><span class="p">()</span>
        <span class="n">switch_file</span> <span class="o">=</span> <span class="n">library_path</span> <span class="o">/</span> <span class="s1">&#39;switches.py&#39;</span>

        <span class="c1"># Switches file found</span>
        <span class="k">if</span> <span class="n">switch_file</span><span class="o">.</span><span class="n">exists</span><span class="p">():</span>
            <span class="n">switches</span> <span class="o">=</span> <span class="bp">cls</span><span class="o">.</span><span class="n">get_switches</span><span class="p">(</span>
                <span class="n">switch_file</span><span class="p">,</span>
                <span class="n">MODULE_PATH</span><span class="o">=</span><span class="n">module_path</span><span class="p">,</span>
                <span class="n">BUILD_ARTIFACT</span><span class="o">=</span><span class="n">build_artifact</span><span class="p">,</span>
                <span class="n">BUILD_DIR</span><span class="o">=</span><span class="kc">None</span><span class="p">,</span>  <span class="c1"># Necessary for import/bundle compatibility</span>
                <span class="n">IS_LIBRARY</span><span class="o">=</span><span class="n">library</span>
            <span class="p">)</span>
            <span class="n">nim_args</span> <span class="o">=</span> <span class="n">switches</span><span class="p">[</span><span class="s1">&#39;import&#39;</span><span class="p">]</span>

        <span class="c1"># Use standard switches</span>
        <span class="k">else</span><span class="p">:</span>
            <span class="n">exe</span> <span class="o">=</span> <span class="p">[(</span><span class="s1">&#39;nimble&#39;</span> <span class="k">if</span> <span class="n">library</span> <span class="k">else</span> <span class="s1">&#39;nim&#39;</span><span class="p">),</span> <span class="s1">&#39;c&#39;</span><span class="p">]</span>
            <span class="n">nim_args</span> <span class="o">=</span> <span class="p">(</span>
                <span class="n">exe</span> <span class="o">+</span> <span class="bp">cls</span><span class="o">.</span><span class="n">NIM_CLI_ARGS</span> <span class="o">+</span>
                <span class="p">[</span><span class="sa">f</span><span class="s1">&#39;--out:</span><span class="si">{build_artifact}</span><span class="s1">&#39;</span><span class="p">,</span> <span class="sa">f</span><span class="s1">&#39;</span><span class="si">{module_path}</span><span class="s1">&#39;</span><span class="p">]</span> <span class="o">+</span>
                <span class="p">([</span><span class="s1">&#39;--accept&#39;</span><span class="p">]</span> <span class="k">if</span> <span class="n">library</span> <span class="k">else</span> <span class="p">[])</span>
            <span class="p">)</span>

        <span class="k">with</span> <span class="n">cd</span><span class="p">(</span><span class="n">library_path</span> <span class="k">if</span> <span class="n">library</span> <span class="k">else</span> <span class="n">Path</span><span class="p">(</span><span class="s1">&#39;.&#39;</span><span class="p">))</span> <span class="k">as</span> <span class="n">tmp_cwd</span><span class="p">:</span>
            <span class="n">output</span><span class="p">,</span> <span class="n">errors</span><span class="p">,</span> <span class="n">warnings</span><span class="p">,</span> <span class="n">hints</span> <span class="o">=</span> <span class="bp">cls</span><span class="o">.</span><span class="n">invoke_compiler</span><span class="p">(</span><span class="n">nim_args</span><span class="p">)</span>

        <span class="k">if</span> <span class="n">errors</span><span class="p">:</span>
            <span class="k">if</span> <span class="n">library</span><span class="p">:</span>
                <span class="k">raise</span> <span class="n">NimInvokeException</span><span class="p">(</span><span class="n">tmp_cwd</span><span class="p">,</span> <span class="n">nim_args</span><span class="p">,</span> <span class="n">errors</span><span class="p">,</span> <span class="n">output</span><span class="p">)</span>
            <span class="k">else</span><span class="p">:</span>
                <span class="k">raise</span> <span class="n">NimCompileException</span><span class="p">(</span><span class="n">errors</span><span class="p">[</span><span class="mi">0</span><span class="p">])</span>

        <span class="k">for</span> <span class="n">warn</span> <span class="ow">in</span> <span class="n">warnings</span><span class="p">:</span> <span class="nb">print</span><span class="p">(</span><span class="n">warn</span><span class="p">)</span>

        <span class="k">return</span> <span class="n">build_artifact</span>
</pre></div>

  </div>
</div>


      <div class="class">
          <h3>Ancestors (in MRO)</h3>
          <ul class="class_list">
          <li><a href="#nimporter.NimCompiler">NimCompiler</a></li>
          <li>builtins.object</li>
          </ul>
          <h3>Class variables</h3>
            <div class="item">
            <p id="nimporter.NimCompiler.EXT" class="name">var <span class="ident">EXT</span></p>
            

            
  
  <div class="source_cont">
</div>

            </div>
            <div class="item">
            <p id="nimporter.NimCompiler.EXT_DIR" class="name">var <span class="ident">EXT_DIR</span></p>
            

            
  
  <div class="source_cont">
</div>

            </div>
            <div class="item">
            <p id="nimporter.NimCompiler.NIM_CLI_ARGS" class="name">var <span class="ident">NIM_CLI_ARGS</span></p>
            

            
  
  <div class="source_cont">
</div>

            </div>
          <h3>Static methods</h3>
            
  <div class="item">
    <div class="name def" id="nimporter.NimCompiler.get_import_prefix">
    <p>def <span class="ident">get_import_prefix</span>(</p><p>module_path, root)</p>
    </div>
    

    
  
    <div class="desc"><p>Computes the proper name of a Nim module amid a given Python project.</p>
<p>This method is needed because Nim Extensions do not automatically know
where they are within a given Python namespace. This method is vital for
recursing through an entire Python project to find every Nim Extension
module and library while preserving the namespace containing each one.</p>
<p>Args:
    module_path(Path): the module for which to determine its namespace.
    root(Path): the path to the Python project containing the Extension.</p>
<p>Returns:
    A tuple of packages containing the given module.</p></div>
  <div class="source_cont">
  <p class="source_link"><a href="javascript:void(0);" onclick="toggle('source-nimporter.NimCompiler.get_import_prefix', this);">Show source &equiv;</a></p>
  <div id="source-nimporter.NimCompiler.get_import_prefix" class="source">
    <div class="codehilite"><pre><span></span><span class="nd">@staticmethod</span>
<span class="k">def</span> <span class="nf">get_import_prefix</span><span class="p">(</span><span class="n">module_path</span><span class="p">,</span> <span class="n">root</span><span class="p">):</span>
    <span class="sd">&quot;&quot;&quot;</span>
<span class="sd">    Computes the proper name of a Nim module amid a given Python project.</span>
<span class="sd">    This method is needed because Nim Extensions do not automatically know</span>
<span class="sd">    where they are within a given Python namespace. This method is vital for</span>
<span class="sd">    recursing through an entire Python project to find every Nim Extension</span>
<span class="sd">    module and library while preserving the namespace containing each one.</span>
<span class="sd">    Args:</span>
<span class="sd">        module_path(Path): the module for which to determine its namespace.</span>
<span class="sd">        root(Path): the path to the Python project containing the Extension.</span>
<span class="sd">    Returns:</span>
<span class="sd">        A tuple of packages containing the given module.</span>
<span class="sd">    &quot;&quot;&quot;</span>
    <span class="n">root_path</span> <span class="o">=</span> <span class="n">root</span><span class="o">.</span><span class="n">resolve</span><span class="p">()</span>
    <span class="n">full_path</span> <span class="o">=</span> <span class="n">module_path</span><span class="o">.</span><span class="n">resolve</span><span class="p">()</span>
    <span class="k">assert</span> <span class="n">full_path</span> <span class="o">&gt;=</span> <span class="n">root_path</span><span class="p">,</span> <span class="s1">&#39;Extension path is not within root dir.&#39;</span>
    <span class="k">return</span> <span class="n">full_path</span><span class="o">.</span><span class="n">parts</span><span class="p">[</span><span class="nb">len</span><span class="p">(</span><span class="n">root_path</span><span class="o">.</span><span class="n">parts</span><span class="p">):]</span>
</pre></div>

  </div>
</div>

  </div>
  
          <h3>Methods</h3>
            
  <div class="item">
    <div class="name def" id="nimporter.NimCompiler.build_artifact">
    <p>def <span class="ident">build_artifact</span>(</p><p>cls, module_path)</p>
    </div>
    

    
  
    <div class="desc"><p>Returns the Path to the built .PYD or .SO. Does not imply it has already
been built.</p>
<p>Args:
    module_path(Path): the path to the module or library.</p>
<p>Returns:
    The path to a build artifact if compilation were to succeed. If the
    module_path is a directory, an appropriate build artifact path
    within that directory is returned.</p></div>
  <div class="source_cont">
  <p class="source_link"><a href="javascript:void(0);" onclick="toggle('source-nimporter.NimCompiler.build_artifact', this);">Show source &equiv;</a></p>
  <div id="source-nimporter.NimCompiler.build_artifact" class="source">
    <div class="codehilite"><pre><span></span><span class="nd">@classmethod</span>
<span class="k">def</span> <span class="nf">build_artifact</span><span class="p">(</span><span class="bp">cls</span><span class="p">,</span> <span class="n">module_path</span><span class="p">):</span>
    <span class="sd">&quot;&quot;&quot;</span>
<span class="sd">    Returns the Path to the built .PYD or .SO. Does not imply it has already</span>
<span class="sd">    been built.</span>
<span class="sd">    Args:</span>
<span class="sd">        module_path(Path): the path to the module or library.</span>
<span class="sd">    Returns:</span>
<span class="sd">        The path to a build artifact if compilation were to succeed. If the</span>
<span class="sd">        module_path is a directory, an appropriate build artifact path</span>
<span class="sd">        within that directory is returned.</span>
<span class="sd">    &quot;&quot;&quot;</span>
    <span class="n">filename</span> <span class="o">=</span> <span class="n">module_path</span><span class="o">.</span><span class="n">stem</span> <span class="o">+</span> <span class="bp">cls</span><span class="o">.</span><span class="n">EXT</span>
    <span class="k">return</span> <span class="p">(</span><span class="bp">cls</span><span class="o">.</span><span class="n">pycache_dir</span><span class="p">(</span><span class="n">module_path</span><span class="p">)</span> <span class="o">/</span> <span class="n">filename</span><span class="p">)</span><span class="o">.</span><span class="n">resolve</span><span class="p">()</span>
</pre></div>

  </div>
</div>

  </div>
  
            
  <div class="item">
    <div class="name def" id="nimporter.NimCompiler.compile_nim_code">
    <p>def <span class="ident">compile_nim_code</span>(</p><p>cls, module_path, build_artifact)</p>
    </div>
    

    
  
    <div class="desc"><p>Returns a Spec object so a Nim module/library can be directly imported.</p>
<p>NOTE: The <code>module_path</code> keyword argument can be either a path to a Nim
file (in the case of <code>library=False</code>) or a path to a directory (in the
case of <code>library=True</code>). However, it has a third supported usage. It can
be a Nim module when <code>library=True</code> and this method will search for the
Nimble file alongside the given path.</p>
<p>NOTE: The library parameter signifies (albeit subtly) that the given Nim
library has (can have) dependencies specified in a Nimble file.</p></div>
  <div class="source_cont">
  <p class="source_link"><a href="javascript:void(0);" onclick="toggle('source-nimporter.NimCompiler.compile_nim_code', this);">Show source &equiv;</a></p>
  <div id="source-nimporter.NimCompiler.compile_nim_code" class="source">
    <div class="codehilite"><pre><span></span><span class="nd">@classmethod</span>
<span class="k">def</span> <span class="nf">compile_nim_code</span><span class="p">(</span><span class="bp">cls</span><span class="p">,</span> <span class="n">module_path</span><span class="p">,</span> <span class="n">build_artifact</span><span class="p">,</span> <span class="o">*</span><span class="p">,</span> <span class="n">library</span><span class="p">:</span> <span class="nb">bool</span><span class="p">):</span>
    <span class="sd">&quot;&quot;&quot;</span>
<span class="sd">    Returns a Spec object so a Nim module/library can be directly imported.</span>
<span class="sd">    NOTE: The `module_path` keyword argument can be either a path to a Nim</span>
<span class="sd">    file (in the case of `library=False`) or a path to a directory (in the</span>
<span class="sd">    case of `library=True`). However, it has a third supported usage. It can</span>
<span class="sd">    be a Nim module when `library=True` and this method will search for the</span>
<span class="sd">    Nimble file alongside the given path.</span>
<span class="sd">    NOTE: The library parameter signifies (albeit subtly) that the given Nim</span>
<span class="sd">    library has (can have) dependencies specified in a Nimble file.</span>
<span class="sd">    &quot;&quot;&quot;</span>
    <span class="k">if</span> <span class="ow">not</span> <span class="n">module_path</span><span class="o">.</span><span class="n">exists</span><span class="p">():</span>
        <span class="k">raise</span> <span class="n">NimporterException</span><span class="p">(</span>
            <span class="sa">f</span><span class="s1">&#39;{module_path.absolute()} does not exist.&#39;</span>
        <span class="p">)</span>
    <span class="k">if</span> <span class="n">library</span> <span class="ow">and</span> <span class="n">module_path</span><span class="o">.</span><span class="n">is_file</span><span class="p">():</span>
        <span class="k">raise</span> <span class="n">NimporterException</span><span class="p">(</span>
            <span class="s1">&#39;Librarys are built using folder name, not specific Nim module&#39;</span>
        <span class="p">)</span>
    <span class="k">elif</span> <span class="ow">not</span> <span class="n">library</span> <span class="ow">and</span> <span class="n">module_path</span><span class="o">.</span><span class="n">is_dir</span><span class="p">():</span>
        <span class="k">raise</span> <span class="n">NimporterException</span><span class="p">(</span>
            <span class="s1">&#39;Modules are built using module name, not containing folder&#39;</span>
        <span class="p">)</span>
    <span class="k">if</span> <span class="n">module_path</span><span class="o">.</span><span class="n">is_file</span><span class="p">():</span>
        <span class="n">library_path</span> <span class="o">=</span> <span class="n">module_path</span><span class="o">.</span><span class="n">parent</span><span class="o">.</span><span class="n">resolve</span><span class="p">()</span>
    <span class="k">elif</span> <span class="n">module_path</span><span class="o">.</span><span class="n">is_dir</span><span class="p">():</span>
        <span class="n">library_path</span> <span class="o">=</span> <span class="n">module_path</span><span class="o">.</span><span class="n">resolve</span><span class="p">()</span>
        <span class="n">module_path</span> <span class="o">=</span> <span class="n">library_path</span> <span class="o">/</span> <span class="p">(</span><span class="n">library_path</span><span class="o">.</span><span class="n">name</span> <span class="o">+</span> <span class="s1">&#39;.nim&#39;</span><span class="p">)</span>
    <span class="k">if</span> <span class="n">library</span> <span class="ow">and</span> <span class="ow">not</span> <span class="nb">any</span><span class="p">(</span><span class="n">library_path</span><span class="o">.</span><span class="n">glob</span><span class="p">(</span><span class="s1">&#39;*.nimble&#39;</span><span class="p">)):</span>
        <span class="k">raise</span> <span class="n">NimporterException</span><span class="p">(</span>
        <span class="sa">f</span><span class="s2">&quot;Library: </span><span class="si">{library_path}</span><span class="s2"> doesn&#39;t contain a .nimble file&quot;</span>
    <span class="p">)</span>
    <span class="bp">cls</span><span class="o">.</span><span class="n">ensure_nimpy</span><span class="p">()</span>
    <span class="n">switch_file</span> <span class="o">=</span> <span class="n">library_path</span> <span class="o">/</span> <span class="s1">&#39;switches.py&#39;</span>
    <span class="c1"># Switches file found</span>
    <span class="k">if</span> <span class="n">switch_file</span><span class="o">.</span><span class="n">exists</span><span class="p">():</span>
        <span class="n">switches</span> <span class="o">=</span> <span class="bp">cls</span><span class="o">.</span><span class="n">get_switches</span><span class="p">(</span>
            <span class="n">switch_file</span><span class="p">,</span>
            <span class="n">MODULE_PATH</span><span class="o">=</span><span class="n">module_path</span><span class="p">,</span>
            <span class="n">BUILD_ARTIFACT</span><span class="o">=</span><span class="n">build_artifact</span><span class="p">,</span>
            <span class="n">BUILD_DIR</span><span class="o">=</span><span class="kc">None</span><span class="p">,</span>  <span class="c1"># Necessary for import/bundle compatibility</span>
            <span class="n">IS_LIBRARY</span><span class="o">=</span><span class="n">library</span>
        <span class="p">)</span>
        <span class="n">nim_args</span> <span class="o">=</span> <span class="n">switches</span><span class="p">[</span><span class="s1">&#39;import&#39;</span><span class="p">]</span>
    <span class="c1"># Use standard switches</span>
    <span class="k">else</span><span class="p">:</span>
        <span class="n">exe</span> <span class="o">=</span> <span class="p">[(</span><span class="s1">&#39;nimble&#39;</span> <span class="k">if</span> <span class="n">library</span> <span class="k">else</span> <span class="s1">&#39;nim&#39;</span><span class="p">),</span> <span class="s1">&#39;c&#39;</span><span class="p">]</span>
        <span class="n">nim_args</span> <span class="o">=</span> <span class="p">(</span>
            <span class="n">exe</span> <span class="o">+</span> <span class="bp">cls</span><span class="o">.</span><span class="n">NIM_CLI_ARGS</span> <span class="o">+</span>
            <span class="p">[</span><span class="sa">f</span><span class="s1">&#39;--out:</span><span class="si">{build_artifact}</span><span class="s1">&#39;</span><span class="p">,</span> <span class="sa">f</span><span class="s1">&#39;</span><span class="si">{module_path}</span><span class="s1">&#39;</span><span class="p">]</span> <span class="o">+</span>
            <span class="p">([</span><span class="s1">&#39;--accept&#39;</span><span class="p">]</span> <span class="k">if</span> <span class="n">library</span> <span class="k">else</span> <span class="p">[])</span>
        <span class="p">)</span>
    <span class="k">with</span> <span class="n">cd</span><span class="p">(</span><span class="n">library_path</span> <span class="k">if</span> <span class="n">library</span> <span class="k">else</span> <span class="n">Path</span><span class="p">(</span><span class="s1">&#39;.&#39;</span><span class="p">))</span> <span class="k">as</span> <span class="n">tmp_cwd</span><span class="p">:</span>
        <span class="n">output</span><span class="p">,</span> <span class="n">errors</span><span class="p">,</span> <span class="n">warnings</span><span class="p">,</span> <span class="n">hints</span> <span class="o">=</span> <span class="bp">cls</span><span class="o">.</span><span class="n">invoke_compiler</span><span class="p">(</span><span class="n">nim_args</span><span class="p">)</span>
    <span class="k">if</span> <span class="n">errors</span><span class="p">:</span>
        <span class="k">if</span> <span class="n">library</span><span class="p">:</span>
            <span class="k">raise</span> <span class="n">NimInvokeException</span><span class="p">(</span><span class="n">tmp_cwd</span><span class="p">,</span> <span class="n">nim_args</span><span class="p">,</span> <span class="n">errors</span><span class="p">,</span> <span class="n">output</span><span class="p">)</span>
        <span class="k">else</span><span class="p">:</span>
            <span class="k">raise</span> <span class="n">NimCompileException</span><span class="p">(</span><span class="n">errors</span><span class="p">[</span><span class="mi">0</span><span class="p">])</span>
    <span class="k">for</span> <span class="n">warn</span> <span class="ow">in</span> <span class="n">warnings</span><span class="p">:</span> <span class="nb">print</span><span class="p">(</span><span class="n">warn</span><span class="p">)</span>
    <span class="k">return</span> <span class="n">build_artifact</span>
</pre></div>

  </div>
</div>

  </div>
  
            
  <div class="item">
    <div class="name def" id="nimporter.NimCompiler.compile_nim_extension">
    <p>def <span class="ident">compile_nim_extension</span>(</p><p>cls, module_path, root)</p>
    </div>
    

    
  
    <div class="desc"><p>Compiles/returns an Extension and installs <code>.nimble</code> dependencies.</p>
<p>Libraries MUST have a Nim file named "<library name>.nim" at the project
root as well as a file ending with ".nimble".</p>
<p>NOTE: The library parameter signifies (albeit subtly) that the given Nim
library has (can have) dependencies specified in a Nimble file.</p>
<p>Args:
    module_path(Path): the path to the library directory or a Nim file.
    root(Path): the path to the directory containing the entire project.
    library(bool): hint as to how to treat the <code>module_path</code> parameter.</p>
<p>Returns:
    An Extension upon successful compilation, else None.</p>
<p>Raises:
    Exception if the library path does not contain the files listed
    above or any other compilation error.</p></div>
  <div class="source_cont">
  <p class="source_link"><a href="javascript:void(0);" onclick="toggle('source-nimporter.NimCompiler.compile_nim_extension', this);">Show source &equiv;</a></p>
  <div id="source-nimporter.NimCompiler.compile_nim_extension" class="source">
    <div class="codehilite"><pre><span></span><span class="nd">@classmethod</span>
<span class="k">def</span> <span class="nf">compile_nim_extension</span><span class="p">(</span><span class="bp">cls</span><span class="p">,</span> <span class="n">module_path</span><span class="p">,</span> <span class="n">root</span><span class="p">,</span> <span class="o">*</span><span class="p">,</span> <span class="n">library</span><span class="p">:</span> <span class="nb">bool</span><span class="p">):</span>
    <span class="sd">&quot;&quot;&quot;</span>
<span class="sd">    Compiles/returns an Extension and installs `.nimble` dependencies.</span>
<span class="sd">    Libraries MUST have a Nim file named &quot;&lt;library name&gt;.nim&quot; at the project</span>
<span class="sd">    root as well as a file ending with &quot;.nimble&quot;.</span>
<span class="sd">    NOTE: The library parameter signifies (albeit subtly) that the given Nim</span>
<span class="sd">    library has (can have) dependencies specified in a Nimble file.</span>
<span class="sd">    Args:</span>
<span class="sd">        module_path(Path): the path to the library directory or a Nim file.</span>
<span class="sd">        root(Path): the path to the directory containing the entire project.</span>
<span class="sd">        library(bool): hint as to how to treat the `module_path` parameter.</span>
<span class="sd">    Returns:</span>
<span class="sd">        An Extension upon successful compilation, else None.</span>
<span class="sd">    Raises:</span>
<span class="sd">        Exception if the library path does not contain the files listed</span>
<span class="sd">        above or any other compilation error.</span>
<span class="sd">    &quot;&quot;&quot;</span>
    <span class="k">if</span> <span class="ow">not</span> <span class="n">module_path</span><span class="o">.</span><span class="n">exists</span><span class="p">():</span>
        <span class="k">raise</span> <span class="n">NimporterException</span><span class="p">(</span>
            <span class="sa">f</span><span class="s1">&#39;{module_path.absolute()} does not exist.&#39;</span>
        <span class="p">)</span>
    <span class="n">module_name</span> <span class="o">=</span> <span class="n">module_path</span><span class="o">.</span><span class="n">stem</span>
    <span class="k">if</span> <span class="n">module_path</span><span class="o">.</span><span class="n">is_file</span><span class="p">():</span>
        <span class="n">library_path</span> <span class="o">=</span> <span class="n">module_path</span><span class="o">.</span><span class="n">parent</span><span class="o">.</span><span class="n">resolve</span><span class="p">()</span>
        
    <span class="k">elif</span> <span class="n">module_path</span><span class="o">.</span><span class="n">is_dir</span><span class="p">():</span>
        <span class="n">library_path</span> <span class="o">=</span> <span class="n">module_path</span><span class="o">.</span><span class="n">resolve</span><span class="p">()</span>
        <span class="n">module_path</span> <span class="o">=</span> <span class="n">library_path</span> <span class="o">/</span> <span class="p">(</span><span class="n">library_path</span><span class="o">.</span><span class="n">name</span> <span class="o">+</span> <span class="s1">&#39;.nim&#39;</span><span class="p">)</span>
    <span class="k">if</span> <span class="n">library</span> <span class="ow">and</span> <span class="ow">not</span> <span class="nb">any</span><span class="p">(</span><span class="n">library_path</span><span class="o">.</span><span class="n">glob</span><span class="p">(</span><span class="s1">&#39;*.nimble&#39;</span><span class="p">)):</span>
        <span class="k">raise</span> <span class="n">NimporterException</span><span class="p">(</span>
        <span class="sa">f</span><span class="s2">&quot;Library: </span><span class="si">{library_path}</span><span class="s2"> doesn&#39;t contain a .nimble file&quot;</span>
    <span class="p">)</span>
    <span class="bp">cls</span><span class="o">.</span><span class="n">ensure_nimpy</span><span class="p">()</span>
    <span class="c1"># Coerce proper import path using root path</span>
    <span class="n">import_prefix</span> <span class="o">=</span> <span class="bp">cls</span><span class="o">.</span><span class="n">get_import_prefix</span><span class="p">(</span><span class="n">module_path</span><span class="o">.</span><span class="n">parent</span><span class="p">,</span> <span class="n">root</span><span class="p">)</span>
    <span class="n">module_part</span> <span class="o">=</span> <span class="nb">tuple</span><span class="p">()</span> <span class="k">if</span> <span class="n">library</span> <span class="k">else</span> <span class="p">(</span><span class="n">module_name</span><span class="p">,)</span>
    <span class="n">import_path</span> <span class="o">=</span> <span class="s1">&#39;.&#39;</span><span class="o">.</span><span class="n">join</span><span class="p">(</span><span class="n">import_prefix</span> <span class="o">+</span> <span class="n">module_part</span><span class="p">)</span>
    <span class="c1"># Record results of build so it can be copied into source archive</span>
    <span class="n">extension_dir</span> <span class="o">=</span> <span class="n">root</span> <span class="o">/</span> <span class="bp">cls</span><span class="o">.</span><span class="n">EXT_DIR</span>
    <span class="n">extension_dir</span><span class="o">.</span><span class="n">mkdir</span><span class="p">(</span><span class="n">parents</span><span class="o">=</span><span class="kc">True</span><span class="p">,</span> <span class="n">exist_ok</span><span class="o">=</span><span class="kc">True</span><span class="p">)</span>
    <span class="n">build_dir</span> <span class="o">=</span> <span class="n">extension_dir</span><span class="o">.</span><span class="n">absolute</span><span class="p">()</span> <span class="o">/</span> <span class="n">import_path</span>
    <span class="n">build_dir</span><span class="o">.</span><span class="n">mkdir</span><span class="p">(</span><span class="n">exist_ok</span><span class="o">=</span><span class="kc">True</span><span class="p">)</span>
    <span class="n">build_dir_relative</span> <span class="o">=</span> <span class="n">extension_dir</span> <span class="o">/</span> <span class="n">import_path</span>
    <span class="c1"># Switches file found</span>
    <span class="n">switch_file</span> <span class="o">=</span> <span class="n">library_path</span> <span class="o">/</span> <span class="s1">&#39;switches.py&#39;</span>
    <span class="k">if</span> <span class="n">switch_file</span><span class="o">.</span><span class="n">exists</span><span class="p">():</span>
        <span class="n">switches</span> <span class="o">=</span> <span class="bp">cls</span><span class="o">.</span><span class="n">get_switches</span><span class="p">(</span>
            <span class="n">switch_file</span><span class="p">,</span>
            <span class="n">MODULE_PATH</span><span class="o">=</span><span class="n">module_path</span><span class="p">,</span>
            <span class="n">BUILD_DIR</span><span class="o">=</span><span class="n">build_dir</span><span class="p">,</span>
            <span class="c1"># Necessary for import/bundle compatibility</span>
            <span class="n">BUILD_ARTIFACT</span><span class="o">=</span><span class="kc">None</span><span class="p">,</span>
            <span class="n">IS_LIBRARY</span><span class="o">=</span><span class="n">library</span>
        <span class="p">)</span>
        <span class="n">nim_args</span> <span class="o">=</span> <span class="n">switches</span><span class="p">[</span><span class="s1">&#39;bundle&#39;</span><span class="p">]</span>
    <span class="c1"># Use standard switches</span>
    <span class="k">else</span><span class="p">:</span>
        <span class="n">exe</span> <span class="o">=</span> <span class="p">[</span><span class="s1">&#39;nimble&#39;</span> <span class="k">if</span> <span class="n">library</span> <span class="k">else</span> <span class="s1">&#39;nim&#39;</span><span class="p">,</span> <span class="s1">&#39;cc&#39;</span><span class="p">,</span> <span class="s1">&#39;-c&#39;</span><span class="p">]</span>
        <span class="n">nim_args</span> <span class="o">=</span> <span class="p">(</span>
            <span class="n">exe</span> <span class="o">+</span> <span class="bp">cls</span><span class="o">.</span><span class="n">NIM_CLI_ARGS</span> <span class="o">+</span>
            <span class="p">[</span><span class="sa">f</span><span class="s1">&#39;--nimcache:</span><span class="si">{build_dir}</span><span class="s1">&#39;</span><span class="p">,</span> <span class="sa">f</span><span class="s1">&#39;</span><span class="si">{module_path}</span><span class="s1">&#39;</span><span class="p">]</span> <span class="o">+</span>
            <span class="p">([</span><span class="s1">&#39;--accept&#39;</span><span class="p">]</span> <span class="k">if</span> <span class="n">library</span> <span class="k">else</span> <span class="p">[])</span>
        <span class="p">)</span>
    <span class="k">with</span> <span class="n">cd</span><span class="p">(</span><span class="n">library_path</span> <span class="k">if</span> <span class="n">library</span> <span class="k">else</span> <span class="n">Path</span><span class="p">(</span><span class="s1">&#39;.&#39;</span><span class="p">))</span> <span class="k">as</span> <span class="n">tmp_cwd</span><span class="p">:</span>
        <span class="n">output</span><span class="p">,</span> <span class="n">errors</span><span class="p">,</span> <span class="n">warnings</span><span class="p">,</span> <span class="n">hints</span> <span class="o">=</span> <span class="bp">cls</span><span class="o">.</span><span class="n">invoke_compiler</span><span class="p">(</span><span class="n">nim_args</span><span class="p">)</span>
    <span class="k">if</span> <span class="n">errors</span><span class="p">:</span>
        <span class="k">if</span> <span class="n">library</span><span class="p">:</span>
            <span class="k">raise</span> <span class="n">NimInvokeException</span><span class="p">(</span><span class="n">tmp_cwd</span><span class="p">,</span> <span class="n">nim_args</span><span class="p">,</span> <span class="n">errors</span><span class="p">,</span> <span class="n">output</span><span class="p">)</span>
        <span class="k">else</span><span class="p">:</span>
            <span class="k">raise</span> <span class="n">NimCompileException</span><span class="p">(</span><span class="n">errors</span><span class="p">[</span><span class="mi">0</span><span class="p">])</span>
    <span class="k">for</span> <span class="n">warn</span> <span class="ow">in</span> <span class="n">warnings</span><span class="p">:</span> <span class="nb">print</span><span class="p">(</span><span class="n">warn</span><span class="p">)</span>
    <span class="n">csources</span> <span class="o">=</span> <span class="p">[</span>
        <span class="nb">str</span><span class="p">(</span><span class="n">c</span><span class="p">)</span> <span class="k">for</span> <span class="n">c</span> <span class="ow">in</span> <span class="n">build_dir_relative</span><span class="o">.</span><span class="n">iterdir</span><span class="p">()</span> <span class="k">if</span> <span class="n">c</span><span class="o">.</span><span class="n">suffix</span> <span class="o">==</span> <span class="s1">&#39;.c&#39;</span>
    <span class="p">]</span>
    <span class="c1"># Copy over needed header(s)</span>
    <span class="n">NIMBASE</span> <span class="o">=</span> <span class="s1">&#39;nimbase.h&#39;</span>
    <span class="n">nimbase</span> <span class="o">=</span> <span class="bp">cls</span><span class="o">.</span><span class="n">find_nim_std_lib</span><span class="p">()</span> <span class="o">/</span> <span class="n">NIMBASE</span>
    <span class="n">nimbase_dest</span> <span class="o">=</span> <span class="nb">str</span><span class="p">(</span><span class="n">build_dir_relative</span> <span class="o">/</span> <span class="n">NIMBASE</span><span class="p">)</span>
    <span class="n">shutil</span><span class="o">.</span><span class="n">copyfile</span><span class="p">(</span><span class="nb">str</span><span class="p">(</span><span class="n">nimbase</span><span class="p">),</span> <span class="n">nimbase_dest</span><span class="p">)</span>
    <span class="c1"># Properly handle bundling headers into the source distribution</span>
    <span class="n">manifest</span> <span class="o">=</span> <span class="n">root</span> <span class="o">/</span> <span class="s1">&#39;MANIFEST.in&#39;</span>
    <span class="k">if</span> <span class="ow">not</span> <span class="n">manifest</span><span class="o">.</span><span class="n">exists</span><span class="p">():</span>
        <span class="n">manifest</span><span class="o">.</span><span class="n">write_text</span><span class="p">(</span><span class="s1">&#39;# NIMPORTER BUNDLE</span><span class="se">\n</span><span class="s1">&#39;</span><span class="p">)</span>
    <span class="k">with</span> <span class="n">manifest</span><span class="o">.</span><span class="n">open</span><span class="p">(</span><span class="s1">&#39;a&#39;</span><span class="p">)</span> <span class="k">as</span> <span class="n">file</span><span class="p">:</span>
        <span class="n">file</span><span class="o">.</span><span class="n">write</span><span class="p">(</span><span class="sa">f</span><span class="s1">&#39;include </span><span class="si">{nimbase_dest}</span><span class="se">\n</span><span class="s1">&#39;</span><span class="p">)</span>
    <span class="k">return</span> <span class="n">Extension</span><span class="p">(</span>
        <span class="n">name</span><span class="o">=</span><span class="n">import_path</span><span class="p">,</span>
        <span class="n">sources</span><span class="o">=</span><span class="n">csources</span><span class="p">,</span>
        <span class="n">include_dirs</span><span class="o">=</span><span class="p">[</span><span class="nb">str</span><span class="p">(</span><span class="n">build_dir</span><span class="p">)]</span>
    <span class="p">)</span>
</pre></div>

  </div>
</div>

  </div>
  
            
  <div class="item">
    <div class="name def" id="nimporter.NimCompiler.ensure_nimpy">
    <p>def <span class="ident">ensure_nimpy</span>(</p><p>cls)</p>
    </div>
    

    
  
    <div class="desc"><p>Makes sure that the Nimpy Nim library is installed.</p>
<p>Verifies that the <a href="https://github.com/yglukhov/nimpy">Nimpy Library</a> is
installed and installs it otherwise.</p>
<p>NOTE: Nimporter would not be possible without Nimpy. Thank you
Yuriy Glukhov for making this project possible!</p></div>
  <div class="source_cont">
  <p class="source_link"><a href="javascript:void(0);" onclick="toggle('source-nimporter.NimCompiler.ensure_nimpy', this);">Show source &equiv;</a></p>
  <div id="source-nimporter.NimCompiler.ensure_nimpy" class="source">
    <div class="codehilite"><pre><span></span><span class="nd">@classmethod</span>
<span class="k">def</span> <span class="nf">ensure_nimpy</span><span class="p">(</span><span class="bp">cls</span><span class="p">):</span>
    <span class="sd">&quot;&quot;&quot;</span>
<span class="sd">    Makes sure that the Nimpy Nim library is installed.</span>
<span class="sd">    Verifies that the [Nimpy Library](https://github.com/yglukhov/nimpy) is</span>
<span class="sd">    installed and installs it otherwise.</span>
<span class="sd">    NOTE: Nimporter would not be possible without Nimpy. Thank you</span>
<span class="sd">    Yuriy Glukhov for making this project possible!</span>
<span class="sd">    &quot;&quot;&quot;</span>
    <span class="n">out</span><span class="p">,</span> <span class="n">errors</span><span class="p">,</span> <span class="n">_</span><span class="p">,</span> <span class="n">_</span> <span class="o">=</span> <span class="bp">cls</span><span class="o">.</span><span class="n">invoke_compiler</span><span class="p">(</span><span class="s1">&#39;nimble path nimpy&#39;</span><span class="o">.</span><span class="n">split</span><span class="p">())</span>
    <span class="k">if</span> <span class="ow">not</span> <span class="n">out</span> <span class="ow">or</span> <span class="n">errors</span><span class="p">:</span>
        <span class="n">nimble_args</span> <span class="o">=</span> <span class="s1">&#39;nimble install nimpy --accept&#39;</span><span class="o">.</span><span class="n">split</span><span class="p">()</span>
        <span class="n">out</span><span class="p">,</span> <span class="n">errors</span><span class="p">,</span> <span class="n">_</span><span class="p">,</span> <span class="n">_</span> <span class="o">=</span> <span class="bp">cls</span><span class="o">.</span><span class="n">invoke_compiler</span><span class="p">(</span><span class="n">nimble_args</span><span class="p">)</span>
    <span class="k">if</span> <span class="n">errors</span><span class="p">:</span> <span class="k">raise</span> <span class="n">NimInvokeException</span><span class="p">(</span><span class="n">Path</span><span class="p">(),</span> <span class="n">nimble_args</span><span class="p">,</span> <span class="n">errors</span><span class="p">,</span> <span class="n">out</span><span class="p">)</span>
</pre></div>

  </div>
</div>

  </div>
  
            
  <div class="item">
    <div class="name def" id="nimporter.NimCompiler.find_nim_std_lib">
    <p>def <span class="ident">find_nim_std_lib</span>(</p><p>cls)</p>
    </div>
    

    
  
    <div class="desc"><p>Finds the path to the <code>lib/</code> directory within a given Nim installation.</p>
<p>Has the ability to find Nim's stdlib on Windows, MacOS, and Linux. Can
also find the stdlib when Nim was installed via Choosenim. Additionally,
it can even find the stdlib of the currently selected toolchain when
using Choosenim.</p>
<p>Returns:
    The Path to the Nim stdlib 'lib' directory if it exists and None
    otherwise.</p></div>
  <div class="source_cont">
  <p class="source_link"><a href="javascript:void(0);" onclick="toggle('source-nimporter.NimCompiler.find_nim_std_lib', this);">Show source &equiv;</a></p>
  <div id="source-nimporter.NimCompiler.find_nim_std_lib" class="source">
    <div class="codehilite"><pre><span></span><span class="nd">@classmethod</span>
<span class="k">def</span> <span class="nf">find_nim_std_lib</span><span class="p">(</span><span class="bp">cls</span><span class="p">):</span>
    <span class="sd">&quot;&quot;&quot;</span>
<span class="sd">    Finds the path to the `lib/` directory within a given Nim installation.</span>
<span class="sd">    Has the ability to find Nim&#39;s stdlib on Windows, MacOS, and Linux. Can</span>
<span class="sd">    also find the stdlib when Nim was installed via Choosenim. Additionally,</span>
<span class="sd">    it can even find the stdlib of the currently selected toolchain when</span>
<span class="sd">    using Choosenim.</span>
<span class="sd">    Returns:</span>
<span class="sd">        The Path to the Nim stdlib &#39;lib&#39; directory if it exists and None</span>
<span class="sd">        otherwise.</span>
<span class="sd">    &quot;&quot;&quot;</span>
    <span class="c1"># Installed via ChooseNim</span>
    <span class="k">if</span> <span class="n">shutil</span><span class="o">.</span><span class="n">which</span><span class="p">(</span><span class="s1">&#39;choosenim&#39;</span><span class="p">):</span>
        <span class="n">o</span><span class="p">,</span> <span class="n">_</span><span class="p">,</span> <span class="n">_</span><span class="p">,</span> <span class="n">_</span> <span class="o">=</span> <span class="bp">cls</span><span class="o">.</span><span class="n">invoke_compiler</span><span class="p">(</span>
            <span class="s1">&#39;choosenim show -y --nocolor&#39;</span><span class="o">.</span><span class="n">split</span><span class="p">()</span>
        <span class="p">)</span>
        <span class="p">(</span><span class="n">choosenim</span><span class="p">,)</span> <span class="o">=</span> <span class="p">[</span><span class="n">i</span> <span class="k">for</span> <span class="n">i</span> <span class="ow">in</span> <span class="n">o</span><span class="o">.</span><span class="n">splitlines</span><span class="p">()</span> <span class="k">if</span> <span class="s1">&#39;Path:&#39;</span> <span class="ow">in</span> <span class="n">i</span><span class="p">]</span>
        <span class="n">toolchain</span> <span class="o">=</span> <span class="n">Path</span><span class="p">(</span><span class="n">choosenim</span><span class="o">.</span><span class="n">split</span><span class="p">(</span><span class="s1">&#39;Path:&#39;</span><span class="p">)</span><span class="o">.</span><span class="n">pop</span><span class="p">()</span><span class="o">.</span><span class="n">strip</span><span class="p">())</span>
        <span class="n">stdlib</span> <span class="o">=</span> <span class="n">toolchain</span> <span class="o">/</span> <span class="s1">&#39;lib&#39;</span>
        <span class="k">if</span> <span class="ow">not</span> <span class="p">(</span><span class="n">stdlib</span> <span class="o">/</span> <span class="s1">&#39;system.nim&#39;</span><span class="p">)</span><span class="o">.</span><span class="n">exists</span><span class="p">():</span>
            <span class="k">return</span> <span class="kc">None</span>
        <span class="k">return</span> <span class="n">stdlib</span><span class="o">.</span><span class="n">resolve</span><span class="p">()</span><span class="o">.</span><span class="n">absolute</span><span class="p">()</span>
    <span class="c1"># Installed manually</span>
    <span class="n">nimexe</span> <span class="o">=</span> <span class="n">shutil</span><span class="o">.</span><span class="n">which</span><span class="p">(</span><span class="s1">&#39;nim&#39;</span><span class="p">)</span>
    <span class="k">if</span> <span class="ow">not</span> <span class="n">nimexe</span><span class="p">:</span>
        <span class="k">return</span> <span class="kc">None</span>
    <span class="n">nimexe</span> <span class="o">=</span> <span class="n">Path</span><span class="p">(</span><span class="n">nimexe</span><span class="p">)</span>
    <span class="n">result</span> <span class="o">=</span> <span class="n">nimexe</span><span class="o">.</span><span class="n">parent</span> <span class="o">/</span> <span class="s1">&#39;../lib&#39;</span>
    <span class="k">if</span> <span class="ow">not</span> <span class="p">(</span><span class="n">result</span> <span class="o">/</span> <span class="s1">&#39;system.nim&#39;</span><span class="p">)</span><span class="o">.</span><span class="n">exists</span><span class="p">():</span>
        <span class="n">result</span> <span class="o">=</span> <span class="n">nimexe</span><span class="o">.</span><span class="n">resolve</span><span class="p">()</span><span class="o">.</span><span class="n">parent</span> <span class="o">/</span> <span class="s1">&#39;../lib&#39;</span>
        <span class="k">if</span> <span class="ow">not</span> <span class="p">(</span><span class="n">result</span> <span class="o">/</span> <span class="s1">&#39;system.nim&#39;</span><span class="p">)</span><span class="o">.</span><span class="n">exists</span><span class="p">():</span>
            <span class="k">return</span> <span class="kc">None</span>
    <span class="k">return</span> <span class="n">result</span><span class="o">.</span><span class="n">resolve</span><span class="p">()</span><span class="o">.</span><span class="n">absolute</span><span class="p">()</span>
</pre></div>

  </div>
</div>

  </div>
  
            
  <div class="item">
    <div class="name def" id="nimporter.NimCompiler.get_switches">
    <p>def <span class="ident">get_switches</span>(</p><p>cls, switch_file, **global_scope)</p>
    </div>
    

    
  
    <div class="desc"><p>Convenience function to return the switches from a given switchfile.</p>
<p>Works by exposing a global scope to the switch file and then evaluating
it. The resulting variable: <code>__switches__</code> should have been defined
within the script which should contain the keys: "import" and "bundle".</p>
<p>The "import" key should be a list of CLI args that should be passed to
the Nim compiler when importing the given Nim library.</p>
<p>The "bundle" key should be a list of CLI args that should be passed to
the Nim compiler when creating an Extension object from the C sources.</p>
<p>When evaluated, the switchfile can make use of a few global variables
that allow it to make certain decisions regarding the outcome of the
compilation:</p>
<ul>
<li><strong>MODULE_PATH</strong>: the path to the actual Nim source file to compile</li>
<li><strong>BUILD_ARTIFACT</strong>: can be used when building a module</li>
<li><strong>BUILD_DIR</strong>: can be used when building a library</li>
<li><strong>IS_LIBRARY</strong>: used to determine if a library/module is being built.</li>
</ul>
<p>The reason for the switchfile being a Python script is that different
platforms will require different compilation switches. The switchfile
author can make use of <code>sys.platform</code> to query platform information.</p>
<p>Returns:
    A dictionary containing the keys: "import" and "bundle", signifying
    the CLI arguments used when importing and building an extension
    module respectively.</p></div>
  <div class="source_cont">
  <p class="source_link"><a href="javascript:void(0);" onclick="toggle('source-nimporter.NimCompiler.get_switches', this);">Show source &equiv;</a></p>
  <div id="source-nimporter.NimCompiler.get_switches" class="source">
    <div class="codehilite"><pre><span></span><span class="nd">@classmethod</span>
<span class="k">def</span> <span class="nf">get_switches</span><span class="p">(</span><span class="bp">cls</span><span class="p">,</span> <span class="n">switch_file</span><span class="p">,</span> <span class="o">**</span><span class="n">global_scope</span><span class="p">):</span>
    <span class="sd">&quot;&quot;&quot;</span>
<span class="sd">    Convenience function to return the switches from a given switchfile.</span>
<span class="sd">    Works by exposing a global scope to the switch file and then evaluating</span>
<span class="sd">    it. The resulting variable: `__switches__` should have been defined</span>
<span class="sd">    within the script which should contain the keys: &quot;import&quot; and &quot;bundle&quot;.</span>
<span class="sd">    The &quot;import&quot; key should be a list of CLI args that should be passed to</span>
<span class="sd">    the Nim compiler when importing the given Nim library.</span>
<span class="sd">    The &quot;bundle&quot; key should be a list of CLI args that should be passed to</span>
<span class="sd">    the Nim compiler when creating an Extension object from the C sources.</span>
<span class="sd">    When evaluated, the switchfile can make use of a few global variables</span>
<span class="sd">    that allow it to make certain decisions regarding the outcome of the</span>
<span class="sd">    compilation:</span>
<span class="sd">     * **MODULE_PATH**: the path to the actual Nim source file to compile</span>
<span class="sd">     * **BUILD_ARTIFACT**: can be used when building a module</span>
<span class="sd">     * **BUILD_DIR**: can be used when building a library</span>
<span class="sd">     * **IS_LIBRARY**: used to determine if a library/module is being built.</span>
<span class="sd">    The reason for the switchfile being a Python script is that different</span>
<span class="sd">    platforms will require different compilation switches. The switchfile</span>
<span class="sd">    author can make use of `sys.platform` to query platform information.</span>
<span class="sd">    Returns:</span>
<span class="sd">        A dictionary containing the keys: &quot;import&quot; and &quot;bundle&quot;, signifying</span>
<span class="sd">        the CLI arguments used when importing and building an extension</span>
<span class="sd">        module respectively.</span>
<span class="sd">    &quot;&quot;&quot;</span>
    <span class="n">global_scope</span> <span class="o">=</span> <span class="n">global_scope</span><span class="o">.</span><span class="n">copy</span><span class="p">()</span>
    <span class="k">assert</span> <span class="n">switch_file</span><span class="o">.</span><span class="n">exists</span><span class="p">(),</span> <span class="p">(</span>
        <span class="s1">&#39;Cannot open nonexistent switch file: &#39;</span> <span class="o">+</span> <span class="nb">str</span><span class="p">(</span><span class="n">switch_file</span><span class="p">)</span>
    <span class="p">)</span>
    <span class="n">exec</span><span class="p">(</span><span class="n">switch_file</span><span class="o">.</span><span class="n">read_text</span><span class="p">(),</span> <span class="n">global_scope</span><span class="p">)</span>
    <span class="k">return</span> <span class="n">global_scope</span><span class="p">[</span><span class="s1">&#39;__switches__&#39;</span><span class="p">]</span>
</pre></div>

  </div>
</div>

  </div>
  
            
  <div class="item">
    <div class="name def" id="nimporter.NimCompiler.invoke_compiler">
    <p>def <span class="ident">invoke_compiler</span>(</p><p>cls, nim_args)</p>
    </div>
    

    
  
    <div class="desc"><p>Invokes the compiler (or any executable) and returns the output.</p>
<p>While this can (and has been) used to call executables other than Nim
and Nimble, it should be noted that the warnings and hints are artifacts
of being mainly targeted as a Nim compiler invoker.</p>
<p>Args:
    nim_args(list): the arg being the executable and the rest are args.</p>
<p>Returns:
    A tuple containing any errors, warnings, or hints from the
    compilation process.</p></div>
  <div class="source_cont">
  <p class="source_link"><a href="javascript:void(0);" onclick="toggle('source-nimporter.NimCompiler.invoke_compiler', this);">Show source &equiv;</a></p>
  <div id="source-nimporter.NimCompiler.invoke_compiler" class="source">
    <div class="codehilite"><pre><span></span><span class="nd">@classmethod</span>
<span class="k">def</span> <span class="nf">invoke_compiler</span><span class="p">(</span><span class="bp">cls</span><span class="p">,</span> <span class="n">nim_args</span><span class="p">:</span> <span class="nb">list</span><span class="p">):</span>
    <span class="sd">&quot;&quot;&quot;</span>
<span class="sd">    Invokes the compiler (or any executable) and returns the output.</span>
<span class="sd">    While this can (and has been) used to call executables other than Nim</span>
<span class="sd">    and Nimble, it should be noted that the warnings and hints are artifacts</span>
<span class="sd">    of being mainly targeted as a Nim compiler invoker.</span>
<span class="sd">    Args:</span>
<span class="sd">        nim_args(list): the arg being the executable and the rest are args.</span>
<span class="sd">    Returns:</span>
<span class="sd">        A tuple containing any errors, warnings, or hints from the</span>
<span class="sd">        compilation process.</span>
<span class="sd">    &quot;&quot;&quot;</span>
    <span class="n">process</span> <span class="o">=</span> <span class="n">subprocess</span><span class="o">.</span><span class="n">run</span><span class="p">(</span>
        <span class="n">nim_args</span><span class="p">,</span> <span class="n">stdout</span><span class="o">=</span><span class="n">subprocess</span><span class="o">.</span><span class="n">PIPE</span><span class="p">,</span> <span class="n">stderr</span><span class="o">=</span><span class="n">subprocess</span><span class="o">.</span><span class="n">PIPE</span>
    <span class="p">)</span>
    <span class="n">out</span><span class="p">,</span> <span class="n">err</span> <span class="o">=</span> <span class="n">process</span><span class="o">.</span><span class="n">stdout</span><span class="p">,</span> <span class="n">process</span><span class="o">.</span><span class="n">stderr</span>
    <span class="n">out</span> <span class="o">=</span> <span class="n">out</span><span class="o">.</span><span class="n">decode</span><span class="p">()</span> <span class="k">if</span> <span class="n">out</span> <span class="k">else</span> <span class="s1">&#39;&#39;</span>
    <span class="n">err</span> <span class="o">=</span> <span class="n">err</span><span class="o">.</span><span class="n">decode</span><span class="p">()</span> <span class="k">if</span> <span class="n">err</span> <span class="k">else</span> <span class="s1">&#39;&#39;</span>
    <span class="n">lines</span> <span class="o">=</span> <span class="p">(</span><span class="n">out</span> <span class="o">+</span> <span class="n">err</span><span class="p">)</span><span class="o">.</span><span class="n">splitlines</span><span class="p">()</span>
    <span class="n">errors</span>   <span class="o">=</span> <span class="p">[</span><span class="n">line</span> <span class="k">for</span> <span class="n">line</span> <span class="ow">in</span> <span class="n">lines</span> <span class="k">if</span> <span class="s1">&#39;Error:&#39;</span> <span class="ow">in</span> <span class="n">line</span><span class="p">]</span>
    <span class="n">warnings</span> <span class="o">=</span> <span class="p">[</span><span class="n">line</span> <span class="k">for</span> <span class="n">line</span> <span class="ow">in</span> <span class="n">lines</span> <span class="k">if</span> <span class="s1">&#39;Warning:&#39;</span> <span class="ow">in</span> <span class="n">line</span><span class="p">]</span>
    <span class="n">hints</span>    <span class="o">=</span> <span class="p">[</span><span class="n">line</span> <span class="k">for</span> <span class="n">line</span> <span class="ow">in</span> <span class="n">lines</span> <span class="k">if</span> <span class="s1">&#39;Hint:&#39;</span> <span class="ow">in</span> <span class="n">line</span><span class="p">]</span>
    <span class="k">return</span> <span class="n">out</span><span class="p">,</span> <span class="n">errors</span><span class="p">,</span> <span class="n">warnings</span><span class="p">,</span> <span class="n">hints</span>
</pre></div>

  </div>
</div>

  </div>
  
            
  <div class="item">
    <div class="name def" id="nimporter.NimCompiler.pycache_dir">
    <p>def <span class="ident">pycache_dir</span>(</p><p>cls, module_path)</p>
    </div>
    

    
  
    <div class="desc"><p>Return the <code>__pycache__</code> directory as a Path.</p>
<p>Works the same as Python's <code>__pycache__</code> directory except now it works
with Nim extensions also. It works literally exactly like Python.</p>
<p>Args:
    module_path(Path): the path to a given Nim module or library.</p>
<p>Returns:
    The Path to the <code>__pycache__</code> directory that the build artifact
    should be stored.</p></div>
  <div class="source_cont">
  <p class="source_link"><a href="javascript:void(0);" onclick="toggle('source-nimporter.NimCompiler.pycache_dir', this);">Show source &equiv;</a></p>
  <div id="source-nimporter.NimCompiler.pycache_dir" class="source">
    <div class="codehilite"><pre><span></span><span class="nd">@classmethod</span>
<span class="k">def</span> <span class="nf">pycache_dir</span><span class="p">(</span><span class="bp">cls</span><span class="p">,</span> <span class="n">module_path</span><span class="p">):</span>
    <span class="sd">&quot;&quot;&quot;</span>
<span class="sd">    Return the `__pycache__` directory as a Path.</span>
<span class="sd">    Works the same as Python&#39;s `__pycache__` directory except now it works</span>
<span class="sd">    with Nim extensions also. It works literally exactly like Python.</span>
<span class="sd">    Args:</span>
<span class="sd">        module_path(Path): the path to a given Nim module or library.</span>
<span class="sd">    Returns:</span>
<span class="sd">        The Path to the `__pycache__` directory that the build artifact</span>
<span class="sd">        should be stored.</span>
<span class="sd">    &quot;&quot;&quot;</span>
    <span class="k">if</span> <span class="n">module_path</span><span class="o">.</span><span class="n">is_dir</span><span class="p">():</span>
        <span class="k">return</span> <span class="p">(</span><span class="n">module_path</span> <span class="o">/</span> <span class="s1">&#39;__pycache__&#39;</span><span class="p">)</span><span class="o">.</span><span class="n">resolve</span><span class="p">()</span>
    <span class="k">else</span><span class="p">:</span>
        <span class="k">return</span> <span class="p">(</span><span class="n">module_path</span><span class="o">.</span><span class="n">parent</span> <span class="o">/</span> <span class="s1">&#39;__pycache__&#39;</span><span class="p">)</span><span class="o">.</span><span class="n">resolve</span><span class="p">()</span>
</pre></div>

  </div>
</div>

  </div>
  
      </div>
      </div>
      
      <div class="item">
      <p id="nimporter.NimInvokeException" class="name">class <span class="ident">NimInvokeException</span></p>
      
  
    <div class="desc"><p>Exception for when a given CLI command fails.</p></div>
  <div class="source_cont">
  <p class="source_link"><a href="javascript:void(0);" onclick="toggle('source-nimporter.NimInvokeException', this);">Show source &equiv;</a></p>
  <div id="source-nimporter.NimInvokeException" class="source">
    <div class="codehilite"><pre><span></span><span class="k">class</span> <span class="nc">NimInvokeException</span><span class="p">(</span><span class="n">NimporterException</span><span class="p">):</span>
    <span class="s2">&quot;Exception for when a given CLI command fails.&quot;</span>

    <span class="k">def</span> <span class="fm">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">cwd</span><span class="p">,</span> <span class="n">cmd_line</span><span class="p">,</span> <span class="n">errors</span><span class="p">,</span> <span class="n">out</span><span class="o">=</span><span class="s1">&#39;&#39;</span><span class="p">):</span>
        <span class="bp">self</span><span class="o">.</span><span class="n">cwd</span> <span class="o">=</span> <span class="n">Path</span><span class="p">(</span><span class="n">cwd</span><span class="p">)</span><span class="o">.</span><span class="n">resolve</span><span class="p">()</span>
        <span class="bp">self</span><span class="o">.</span><span class="n">cmd_line</span> <span class="o">=</span> <span class="n">cmd_line</span>
        <span class="bp">self</span><span class="o">.</span><span class="n">errors</span> <span class="o">=</span> <span class="n">errors</span>
        <span class="bp">self</span><span class="o">.</span><span class="n">out</span> <span class="o">=</span> <span class="n">out</span>

    <span class="k">def</span> <span class="nf">get_output</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
        <span class="s2">&quot;Return the output (if any) of the CLI command that caused the error.&quot;</span>
        <span class="k">return</span> <span class="bp">self</span><span class="o">.</span><span class="n">out</span>

    <span class="k">def</span> <span class="fm">__str__</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
        <span class="s2">&quot;Return the string representation of the error.&quot;</span>
        <span class="n">cmd</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">cmd_line</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span>
        <span class="n">message</span> <span class="o">=</span> <span class="sa">f</span><span class="s1">&#39;Failed to run command: </span><span class="si">{cmd}</span><span class="se">\n\n</span><span class="s1">&#39;</span>
        <span class="n">message</span> <span class="o">+=</span> <span class="sa">f</span><span class="s1">&#39;Current Directory:</span><span class="se">\n</span><span class="s1">    </span><span class="si">{self.cwd}</span><span class="se">\n\n</span><span class="s1">&#39;</span>
        <span class="n">message</span> <span class="o">+=</span> <span class="sa">f</span><span class="s1">&#39;Error Message:</span><span class="se">\n</span><span class="s1">&#39;</span>
        <span class="n">message</span> <span class="o">+=</span> <span class="s1">&#39;</span><span class="se">\n</span><span class="s1">    &#39;</span><span class="o">.</span><span class="n">join</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">errors</span><span class="p">)</span> <span class="o">+</span> <span class="s1">&#39;</span><span class="se">\n\n</span><span class="s1">&#39;</span>
        <span class="n">message</span> <span class="o">+=</span> <span class="sa">f</span><span class="s1">&#39;Command Line Arguments:</span><span class="se">\n</span><span class="s1">    </span><span class="si">{cmd}</span><span class="se">\n</span><span class="s1">&#39;</span>
        <span class="k">for</span> <span class="n">arg</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">cmd_line</span><span class="p">[</span><span class="mi">1</span><span class="p">:]:</span>
            <span class="n">message</span> <span class="o">+=</span> <span class="sa">f</span><span class="s1">&#39;        </span><span class="si">{arg}</span><span class="se">\n</span><span class="s1">&#39;</span>
        <span class="k">return</span> <span class="n">message</span>
</pre></div>

  </div>
</div>


      <div class="class">
          <h3>Ancestors (in MRO)</h3>
          <ul class="class_list">
          <li><a href="#nimporter.NimInvokeException">NimInvokeException</a></li>
          <li><a href="#nimporter.NimporterException">NimporterException</a></li>
          <li>builtins.Exception</li>
          <li>builtins.BaseException</li>
          <li>builtins.object</li>
          </ul>
          <h3>Class variables</h3>
            <div class="item">
            <p id="nimporter.NimInvokeException.args" class="name">var <span class="ident">args</span></p>
            

            
  
  <div class="source_cont">
</div>

            </div>
          <h3>Static methods</h3>
            
  <div class="item">
    <div class="name def" id="nimporter.NimInvokeException.__init__">
    <p>def <span class="ident">__init__</span>(</p><p>self, cwd, cmd_line, errors, out=&#39;&#39;)</p>
    </div>
    

    
  
    <div class="desc"><p>Initialize self.  See help(type(self)) for accurate signature.</p></div>
  <div class="source_cont">
  <p class="source_link"><a href="javascript:void(0);" onclick="toggle('source-nimporter.NimInvokeException.__init__', this);">Show source &equiv;</a></p>
  <div id="source-nimporter.NimInvokeException.__init__" class="source">
    <div class="codehilite"><pre><span></span><span class="k">def</span> <span class="fm">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">cwd</span><span class="p">,</span> <span class="n">cmd_line</span><span class="p">,</span> <span class="n">errors</span><span class="p">,</span> <span class="n">out</span><span class="o">=</span><span class="s1">&#39;&#39;</span><span class="p">):</span>
    <span class="bp">self</span><span class="o">.</span><span class="n">cwd</span> <span class="o">=</span> <span class="n">Path</span><span class="p">(</span><span class="n">cwd</span><span class="p">)</span><span class="o">.</span><span class="n">resolve</span><span class="p">()</span>
    <span class="bp">self</span><span class="o">.</span><span class="n">cmd_line</span> <span class="o">=</span> <span class="n">cmd_line</span>
    <span class="bp">self</span><span class="o">.</span><span class="n">errors</span> <span class="o">=</span> <span class="n">errors</span>
    <span class="bp">self</span><span class="o">.</span><span class="n">out</span> <span class="o">=</span> <span class="n">out</span>
</pre></div>

  </div>
</div>

  </div>
  
            
  <div class="item">
    <div class="name def" id="nimporter.NimInvokeException.get_output">
    <p>def <span class="ident">get_output</span>(</p><p>self)</p>
    </div>
    

    
  
    <div class="desc"><p>Return the output (if any) of the CLI command that caused the error.</p></div>
  <div class="source_cont">
  <p class="source_link"><a href="javascript:void(0);" onclick="toggle('source-nimporter.NimInvokeException.get_output', this);">Show source &equiv;</a></p>
  <div id="source-nimporter.NimInvokeException.get_output" class="source">
    <div class="codehilite"><pre><span></span><span class="k">def</span> <span class="nf">get_output</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
    <span class="s2">&quot;Return the output (if any) of the CLI command that caused the error.&quot;</span>
    <span class="k">return</span> <span class="bp">self</span><span class="o">.</span><span class="n">out</span>
</pre></div>

  </div>
</div>

  </div>
  
          <h3>Instance variables</h3>
            <div class="item">
            <p id="nimporter.NimInvokeException.cmd_line" class="name">var <span class="ident">cmd_line</span></p>
            

            
  
  <div class="source_cont">
</div>

            </div>
            <div class="item">
            <p id="nimporter.NimInvokeException.cwd" class="name">var <span class="ident">cwd</span></p>
            

            
  
  <div class="source_cont">
</div>

            </div>
            <div class="item">
            <p id="nimporter.NimInvokeException.errors" class="name">var <span class="ident">errors</span></p>
            

            
  
  <div class="source_cont">
</div>

            </div>
            <div class="item">
            <p id="nimporter.NimInvokeException.out" class="name">var <span class="ident">out</span></p>
            

            
  
  <div class="source_cont">
</div>

            </div>
      </div>
      </div>
      
      <div class="item">
      <p id="nimporter.NimLibImporter" class="name">class <span class="ident">NimLibImporter</span></p>
      
  
    <div class="desc"><p>Extends Python import machinery to be able to import Nim libraries.</p>
<p>NOTE: Must be placed at the front of <code>sys.meta_path</code> because of how Python
treats folders when imported.</p>
<p>Before NimLibImporter can attempt to find a folder containing a Nimble file
containing dependency info and a corresponding Nim module, Python's import
machinery imports the folder as a <code>namspace</code> type.</p>
<p>The only way to allow NimLibImporter to get a chance to import Nim libraries
is to put it at the front of <code>sys.meta_path</code>. However, this has a small side
effect of making Nim libraries have precedence over Python namespaces.</p>
<p>This should never have any adverse effects since the criterion for a Nim
library in relation to Nimporter is to have a folder containing a Nim module
and a Nimble file with the same name as the folder. By placing both of those
files into a directory, it should be extremely clear that the given folder
is a Nim library.</p>
<p>Additionally, this also means that a Nim library cannot contain any Python
modules.</p></div>
  <div class="source_cont">
  <p class="source_link"><a href="javascript:void(0);" onclick="toggle('source-nimporter.NimLibImporter', this);">Show source &equiv;</a></p>
  <div id="source-nimporter.NimLibImporter" class="source">
    <div class="codehilite"><pre><span></span><span class="k">class</span> <span class="nc">NimLibImporter</span><span class="p">:</span>
    <span class="sd">&quot;&quot;&quot;</span>
<span class="sd">    Extends Python import machinery to be able to import Nim libraries.</span>

<span class="sd">    NOTE: Must be placed at the front of `sys.meta_path` because of how Python</span>
<span class="sd">    treats folders when imported.</span>

<span class="sd">    Before NimLibImporter can attempt to find a folder containing a Nimble file</span>
<span class="sd">    containing dependency info and a corresponding Nim module, Python&#39;s import</span>
<span class="sd">    machinery imports the folder as a `namspace` type.</span>

<span class="sd">    The only way to allow NimLibImporter to get a chance to import Nim libraries</span>
<span class="sd">    is to put it at the front of `sys.meta_path`. However, this has a small side</span>
<span class="sd">    effect of making Nim libraries have precedence over Python namespaces.</span>

<span class="sd">    This should never have any adverse effects since the criterion for a Nim</span>
<span class="sd">    library in relation to Nimporter is to have a folder containing a Nim module</span>
<span class="sd">    and a Nimble file with the same name as the folder. By placing both of those</span>
<span class="sd">    files into a directory, it should be extremely clear that the given folder</span>
<span class="sd">    is a Nim library.</span>

<span class="sd">    Additionally, this also means that a Nim library cannot contain any Python</span>
<span class="sd">    modules.</span>
<span class="sd">    &quot;&quot;&quot;</span>

    <span class="nd">@classmethod</span>
    <span class="k">def</span> <span class="nf">find_spec</span><span class="p">(</span><span class="bp">cls</span><span class="p">,</span> <span class="n">fullname</span><span class="p">,</span> <span class="n">path</span><span class="o">=</span><span class="kc">None</span><span class="p">,</span> <span class="n">target</span><span class="o">=</span><span class="kc">None</span><span class="p">):</span>
        <span class="k">return</span> <span class="n">Nimporter</span><span class="o">.</span><span class="n">import_nim_code</span><span class="p">(</span><span class="n">fullname</span><span class="p">,</span> <span class="n">path</span><span class="p">,</span> <span class="n">library</span><span class="o">=</span><span class="kc">True</span><span class="p">)</span>
</pre></div>

  </div>
</div>


      <div class="class">
          <h3>Ancestors (in MRO)</h3>
          <ul class="class_list">
          <li><a href="#nimporter.NimLibImporter">NimLibImporter</a></li>
          <li>builtins.object</li>
          </ul>
          <h3>Methods</h3>
            
  <div class="item">
    <div class="name def" id="nimporter.NimLibImporter.find_spec">
    <p>def <span class="ident">find_spec</span>(</p><p>cls, fullname, path=None, target=None)</p>
    </div>
    

    
  
  <div class="source_cont">
  <p class="source_link"><a href="javascript:void(0);" onclick="toggle('source-nimporter.NimLibImporter.find_spec', this);">Show source &equiv;</a></p>
  <div id="source-nimporter.NimLibImporter.find_spec" class="source">
    <div class="codehilite"><pre><span></span><span class="nd">@classmethod</span>
<span class="k">def</span> <span class="nf">find_spec</span><span class="p">(</span><span class="bp">cls</span><span class="p">,</span> <span class="n">fullname</span><span class="p">,</span> <span class="n">path</span><span class="o">=</span><span class="kc">None</span><span class="p">,</span> <span class="n">target</span><span class="o">=</span><span class="kc">None</span><span class="p">):</span>
    <span class="k">return</span> <span class="n">Nimporter</span><span class="o">.</span><span class="n">import_nim_code</span><span class="p">(</span><span class="n">fullname</span><span class="p">,</span> <span class="n">path</span><span class="p">,</span> <span class="n">library</span><span class="o">=</span><span class="kc">True</span><span class="p">)</span>
</pre></div>

  </div>
</div>

  </div>
  
      </div>
      </div>
      
      <div class="item">
      <p id="nimporter.NimModImporter" class="name">class <span class="ident">NimModImporter</span></p>
      
  
    <div class="desc"><p>Extends Python import machinery to be able to import Nim modules.</p>
<p>NOTE: Must be placed at the back of <code>sys.meta_path</code> because Python modules
should be given precedence over Nim modules.</p>
<p>Nim Modules can be placed anywhere that Python modules can. However, if a
Python module and a Nim module with the same name are in the same package,
the Python module will be imported.</p></div>
  <div class="source_cont">
  <p class="source_link"><a href="javascript:void(0);" onclick="toggle('source-nimporter.NimModImporter', this);">Show source &equiv;</a></p>
  <div id="source-nimporter.NimModImporter" class="source">
    <div class="codehilite"><pre><span></span><span class="k">class</span> <span class="nc">NimModImporter</span><span class="p">:</span>
    <span class="sd">&quot;&quot;&quot;</span>
<span class="sd">    Extends Python import machinery to be able to import Nim modules.</span>

<span class="sd">    NOTE: Must be placed at the back of `sys.meta_path` because Python modules</span>
<span class="sd">    should be given precedence over Nim modules.</span>

<span class="sd">    Nim Modules can be placed anywhere that Python modules can. However, if a</span>
<span class="sd">    Python module and a Nim module with the same name are in the same package,</span>
<span class="sd">    the Python module will be imported.</span>
<span class="sd">    &quot;&quot;&quot;</span>

    <span class="nd">@classmethod</span>
    <span class="k">def</span> <span class="nf">find_spec</span><span class="p">(</span><span class="bp">cls</span><span class="p">,</span> <span class="n">fullname</span><span class="p">,</span> <span class="n">path</span><span class="o">=</span><span class="kc">None</span><span class="p">,</span> <span class="n">target</span><span class="o">=</span><span class="kc">None</span><span class="p">):</span>
        <span class="k">return</span> <span class="n">Nimporter</span><span class="o">.</span><span class="n">import_nim_code</span><span class="p">(</span><span class="n">fullname</span><span class="p">,</span> <span class="n">path</span><span class="p">,</span> <span class="n">library</span><span class="o">=</span><span class="kc">False</span><span class="p">)</span>
</pre></div>

  </div>
</div>


      <div class="class">
          <h3>Ancestors (in MRO)</h3>
          <ul class="class_list">
          <li><a href="#nimporter.NimModImporter">NimModImporter</a></li>
          <li>builtins.object</li>
          </ul>
          <h3>Methods</h3>
            
  <div class="item">
    <div class="name def" id="nimporter.NimModImporter.find_spec">
    <p>def <span class="ident">find_spec</span>(</p><p>cls, fullname, path=None, target=None)</p>
    </div>
    

    
  
  <div class="source_cont">
  <p class="source_link"><a href="javascript:void(0);" onclick="toggle('source-nimporter.NimModImporter.find_spec', this);">Show source &equiv;</a></p>
  <div id="source-nimporter.NimModImporter.find_spec" class="source">
    <div class="codehilite"><pre><span></span><span class="nd">@classmethod</span>
<span class="k">def</span> <span class="nf">find_spec</span><span class="p">(</span><span class="bp">cls</span><span class="p">,</span> <span class="n">fullname</span><span class="p">,</span> <span class="n">path</span><span class="o">=</span><span class="kc">None</span><span class="p">,</span> <span class="n">target</span><span class="o">=</span><span class="kc">None</span><span class="p">):</span>
    <span class="k">return</span> <span class="n">Nimporter</span><span class="o">.</span><span class="n">import_nim_code</span><span class="p">(</span><span class="n">fullname</span><span class="p">,</span> <span class="n">path</span><span class="p">,</span> <span class="n">library</span><span class="o">=</span><span class="kc">False</span><span class="p">)</span>
</pre></div>

  </div>
</div>

  </div>
  
      </div>
      </div>
      
      <div class="item">
      <p id="nimporter.Nimporter" class="name">class <span class="ident">Nimporter</span></p>
      
  
    <div class="desc"><p>Python module finder purpose-built to find Nim modules on the Python PATH,
compile them, hide them within the <strong>pycache</strong> directory with other compiled
Python files, and then return it as a full Python module.
This Nimporter can only import Nim modules with procedures exposed via the
<a href="https://github.com/yglukhov/nimpy">Nimpy</a> library acting as a bridge.</p>
<p>Atrributes:
    IGNORE_CACHE(bool): when True, will always trigger a rebuild of any Nim
        modules. Can be set by the importer of this module.</p></div>
  <div class="source_cont">
  <p class="source_link"><a href="javascript:void(0);" onclick="toggle('source-nimporter.Nimporter', this);">Show source &equiv;</a></p>
  <div id="source-nimporter.Nimporter" class="source">
    <div class="codehilite"><pre><span></span><span class="k">class</span> <span class="nc">Nimporter</span><span class="p">:</span>
    <span class="sd">&quot;&quot;&quot;</span>
<span class="sd">    Python module finder purpose-built to find Nim modules on the Python PATH,</span>
<span class="sd">    compile them, hide them within the __pycache__ directory with other compiled</span>
<span class="sd">    Python files, and then return it as a full Python module.</span>
<span class="sd">    This Nimporter can only import Nim modules with procedures exposed via the</span>
<span class="sd">    [Nimpy](https://github.com/yglukhov/nimpy) library acting as a bridge.</span>

<span class="sd">    Atrributes:</span>
<span class="sd">        IGNORE_CACHE(bool): when True, will always trigger a rebuild of any Nim</span>
<span class="sd">            modules. Can be set by the importer of this module.</span>
<span class="sd">    &quot;&quot;&quot;</span>
    <span class="n">IGNORE_CACHE</span> <span class="o">=</span> <span class="kc">False</span>

    <span class="nd">@classmethod</span>
    <span class="k">def</span> <span class="nf">hash_filename</span><span class="p">(</span><span class="bp">cls</span><span class="p">,</span> <span class="n">module_path</span><span class="p">):</span>
        <span class="sd">&quot;&quot;&quot;</span>
<span class="sd">        Gets the filename that should contain a given module&#39;s hash.</span>
<span class="sd">    </span>
<span class="sd">        Args:</span>
<span class="sd">            module_path(Path): the Nim module the hash file pertains to.</span>

<span class="sd">        Returns:</span>
<span class="sd">            The hash filename as a Path.</span>
<span class="sd">        &quot;&quot;&quot;</span>
        <span class="k">return</span> <span class="p">(</span>
            <span class="n">NimCompiler</span><span class="o">.</span><span class="n">pycache_dir</span><span class="p">(</span><span class="n">module_path</span><span class="p">)</span> <span class="o">/</span> <span class="p">(</span><span class="n">module_path</span><span class="o">.</span><span class="n">name</span> <span class="o">+</span> <span class="s1">&#39;.hash&#39;</span><span class="p">)</span>
        <span class="p">)</span>

    <span class="nd">@classmethod</span>
    <span class="k">def</span> <span class="nf">is_cache</span><span class="p">(</span><span class="bp">cls</span><span class="p">,</span> <span class="n">module_path</span><span class="p">):</span>
        <span class="sd">&quot;&quot;&quot;</span>
<span class="sd">        Determines if the `__pycache__` dir for a given Nim module exists.</span>

<span class="sd">        Args:</span>
<span class="sd">            module_path(Path): the Nim module the `__pycache__` dir pertains to.</span>

<span class="sd">        Returns:</span>
<span class="sd">            A bool indicating whether or not a __pycache__ directory exists to</span>
<span class="sd">            store hashes and build artifacts.</span>
<span class="sd">        &quot;&quot;&quot;</span>
        <span class="k">return</span> <span class="n">NimCompiler</span><span class="o">.</span><span class="n">pycache_dir</span><span class="p">(</span><span class="n">module_path</span><span class="p">)</span><span class="o">.</span><span class="n">exists</span><span class="p">()</span>

    <span class="nd">@classmethod</span>
    <span class="k">def</span> <span class="nf">is_hashed</span><span class="p">(</span><span class="bp">cls</span><span class="p">,</span> <span class="n">module_path</span><span class="p">):</span>
        <span class="sd">&quot;&quot;&quot;</span>
<span class="sd">        Determines if a given Nim module has already been hashed.</span>

<span class="sd">        Args:</span>
<span class="sd">            module_path(Path): the Nim module for which to query hash existence.</span>

<span class="sd">        Returns:</span>
<span class="sd">            A bool indicating whether or not a given Nim file has already been</span>
<span class="sd">            hashed.</span>
<span class="sd">        &quot;&quot;&quot;</span>
        <span class="k">return</span> <span class="bp">cls</span><span class="o">.</span><span class="n">hash_filename</span><span class="p">(</span><span class="n">module_path</span><span class="p">)</span><span class="o">.</span><span class="n">exists</span><span class="p">()</span>

    <span class="nd">@classmethod</span>
    <span class="k">def</span> <span class="nf">is_built</span><span class="p">(</span><span class="bp">cls</span><span class="p">,</span> <span class="n">module_path</span><span class="p">):</span>
        <span class="sd">&quot;&quot;&quot;</span>
<span class="sd">        Determines if a given Nim module has already been built.</span>

<span class="sd">        Args:</span>
<span class="sd">            module_path(Path): the Nim module for which to query for artifacts.</span>

<span class="sd">        Returns:</span>
<span class="sd">            A bool indicating whether or not a given Nim file has already been</span>
<span class="sd">            built.</span>
<span class="sd">        &quot;&quot;&quot;</span>
        <span class="k">return</span> <span class="n">NimCompiler</span><span class="o">.</span><span class="n">build_artifact</span><span class="p">(</span><span class="n">module_path</span><span class="p">)</span><span class="o">.</span><span class="n">exists</span><span class="p">()</span>

    <span class="nd">@classmethod</span>
    <span class="k">def</span> <span class="nf">get_hash</span><span class="p">(</span><span class="bp">cls</span><span class="p">,</span> <span class="n">module_path</span><span class="p">):</span>
        <span class="sd">&quot;&quot;&quot;</span>
<span class="sd">        Gathers the hash for a given Nim module.</span>

<span class="sd">        Args:</span>
<span class="sd">            module_path(Path): the Nim module for which to return its hash.</span>

<span class="sd">        Raises:</span>
<span class="sd">            NimporterException: if the module has not yet been hashed.</span>

<span class="sd">        Returns:</span>
<span class="sd">            The bytes of the hash for a given Nim module.</span>
<span class="sd">        &quot;&quot;&quot;</span>
        <span class="k">if</span> <span class="ow">not</span> <span class="bp">cls</span><span class="o">.</span><span class="n">is_hashed</span><span class="p">(</span><span class="n">module_path</span><span class="p">):</span>
            <span class="n">path</span> <span class="o">=</span> <span class="n">module_path</span><span class="o">.</span><span class="n">absolute</span><span class="p">()</span>
            <span class="k">raise</span> <span class="n">NimporterException</span><span class="p">(</span><span class="sa">f</span><span class="s1">&#39;Module </span><span class="si">{path}</span><span class="s1"> has not yet been hashed.&#39;</span><span class="p">)</span>
        <span class="k">return</span> <span class="bp">cls</span><span class="o">.</span><span class="n">hash_filename</span><span class="p">(</span><span class="n">module_path</span><span class="p">)</span><span class="o">.</span><span class="n">read_bytes</span><span class="p">()</span>

    <span class="nd">@classmethod</span>
    <span class="k">def</span> <span class="nf">hash_changed</span><span class="p">(</span><span class="bp">cls</span><span class="p">,</span> <span class="n">module_path</span><span class="p">):</span>
        <span class="sd">&quot;&quot;&quot;</span>
<span class="sd">        Determines if a module has been modified.</span>

<span class="sd">        Args:</span>
<span class="sd">            module_path(Path): the Nim module to check for modification.</span>

<span class="sd">        Returns:</span>
<span class="sd">            A bool indicating whether or not a given Nim file has changed since</span>
<span class="sd">            last hash. If the module has not yet been hashed, returns True.</span>
<span class="sd">        &quot;&quot;&quot;</span>
        <span class="k">if</span> <span class="ow">not</span> <span class="bp">cls</span><span class="o">.</span><span class="n">is_hashed</span><span class="p">(</span><span class="n">module_path</span><span class="p">):</span>
            <span class="k">return</span> <span class="kc">True</span>
        <span class="k">return</span> <span class="bp">cls</span><span class="o">.</span><span class="n">get_hash</span><span class="p">(</span><span class="n">module_path</span><span class="p">)</span> <span class="o">!=</span> <span class="bp">cls</span><span class="o">.</span><span class="n">hash_file</span><span class="p">(</span><span class="n">module_path</span><span class="p">)</span>

    <span class="nd">@staticmethod</span>
    <span class="k">def</span> <span class="nf">hash_file</span><span class="p">(</span><span class="n">module_path</span><span class="p">):</span>
        <span class="sd">&quot;&quot;&quot;</span>
<span class="sd">        Convenience function to hash a given file.</span>

<span class="sd">        Args:</span>
<span class="sd">            module_path(Path): the file to hash.</span>
<span class="sd">        </span>
<span class="sd">        Returns:</span>
<span class="sd">            The hash bytes of the Nim file.</span>
<span class="sd">        &quot;&quot;&quot;</span>
        <span class="n">block_size</span> <span class="o">=</span> <span class="mi">65536</span>
        <span class="n">hasher</span> <span class="o">=</span> <span class="n">hashlib</span><span class="o">.</span><span class="n">md5</span><span class="p">()</span>
        <span class="k">with</span> <span class="n">module_path</span><span class="o">.</span><span class="n">open</span><span class="p">(</span><span class="s1">&#39;rb&#39;</span><span class="p">)</span> <span class="k">as</span> <span class="n">file</span><span class="p">:</span>
            <span class="n">buf</span> <span class="o">=</span> <span class="n">file</span><span class="o">.</span><span class="n">read</span><span class="p">(</span><span class="n">block_size</span><span class="p">)</span>
            <span class="k">while</span> <span class="nb">len</span><span class="p">(</span><span class="n">buf</span><span class="p">)</span> <span class="o">&gt;</span> <span class="mi">0</span><span class="p">:</span>
                <span class="n">hasher</span><span class="o">.</span><span class="n">update</span><span class="p">(</span><span class="n">buf</span><span class="p">)</span>
                <span class="n">buf</span> <span class="o">=</span> <span class="n">file</span><span class="o">.</span><span class="n">read</span><span class="p">(</span><span class="n">block_size</span><span class="p">)</span>
        <span class="k">return</span> <span class="n">hasher</span><span class="o">.</span><span class="n">digest</span><span class="p">()</span>

    <span class="nd">@classmethod</span>
    <span class="k">def</span> <span class="nf">update_hash</span><span class="p">(</span><span class="bp">cls</span><span class="p">,</span> <span class="n">module_path</span><span class="p">):</span>
        <span class="sd">&quot;&quot;&quot;</span>
<span class="sd">        Updates the hash file associated with a given Nim module.</span>

<span class="sd">        This is commonly done after compilation to determine if recompilation is</span>
<span class="sd">        required upon subsequent imports. If the module&#39;s hash file has not yet</span>
<span class="sd">        been created, this method will create it and store it in the</span>
<span class="sd">        `__pycache__` dir for the module.</span>

<span class="sd">        Args:</span>
<span class="sd">            module_path(Path): the module which should have its hash updated.</span>
<span class="sd">        &quot;&quot;&quot;</span>
        <span class="n">hash_file</span> <span class="o">=</span> <span class="bp">cls</span><span class="o">.</span><span class="n">hash_filename</span><span class="p">(</span><span class="n">module_path</span><span class="p">)</span>
        <span class="n">hash_file</span><span class="o">.</span><span class="n">parent</span><span class="o">.</span><span class="n">mkdir</span><span class="p">(</span><span class="n">parents</span><span class="o">=</span><span class="kc">True</span><span class="p">,</span> <span class="n">exist_ok</span><span class="o">=</span><span class="kc">True</span><span class="p">)</span>
        <span class="k">with</span> <span class="n">hash_file</span><span class="o">.</span><span class="n">open</span><span class="p">(</span><span class="s1">&#39;wb&#39;</span><span class="p">)</span> <span class="k">as</span> <span class="n">file</span><span class="p">:</span>
            <span class="n">file</span><span class="o">.</span><span class="n">write</span><span class="p">(</span><span class="bp">cls</span><span class="o">.</span><span class="n">hash_file</span><span class="p">(</span><span class="n">module_path</span><span class="p">))</span>

    <span class="nd">@classmethod</span>
    <span class="k">def</span> <span class="nf">import_nim_module</span><span class="p">(</span><span class="bp">cls</span><span class="p">,</span> <span class="n">fullname</span><span class="p">,</span> <span class="n">path</span><span class="p">:</span><span class="nb">list</span><span class="o">=</span><span class="kc">None</span><span class="p">,</span> <span class="n">ignore_cache</span><span class="o">=</span><span class="kc">None</span><span class="p">):</span>
        <span class="sd">&quot;&quot;&quot;</span>
<span class="sd">        Convenience function to manually import a given Nim module or library.</span>

<span class="sd">        Can be used to explicitly import a module rather than using the `import`</span>
<span class="sd">        keyword. Allows the cache to be ignored to solve issues arising from</span>
<span class="sd">        caching one module when 10 other imported Nim libraries have changed.</span>

<span class="sd">        Example Use:</span>

<span class="sd">            # Rather than:</span>
<span class="sd">            import foo</span>
<span class="sd">            # You can say:</span>
<span class="sd">            foo = Nimporter.import_nim_module(&#39;foo&#39;, [&#39;/some/random/dir&#39;])</span>

<span class="sd">        Args:</span>
<span class="sd">            fullname(str): the module to import. Can be &#39;foo&#39; or &#39;foo.bar.baz&#39;</span>
<span class="sd">            path(list): a list of paths to search first.</span>
<span class="sd">            ignore_cache(bool): whether or not to use a cached build if found.</span>

<span class="sd">        Returns:</span>
<span class="sd">            The Python Module object representing the imported PYD or SO file.            </span>
<span class="sd">        &quot;&quot;&quot;</span>
        <span class="k">if</span> <span class="n">ignore_cache</span> <span class="o">!=</span> <span class="kc">None</span><span class="p">:</span>
            <span class="n">tmp</span> <span class="o">=</span> <span class="bp">cls</span><span class="o">.</span><span class="n">IGNORE_CACHE</span>
            <span class="bp">cls</span><span class="o">.</span><span class="n">IGNORE_CACHE</span> <span class="o">=</span> <span class="n">ignore_cache</span>

        <span class="k">try</span><span class="p">:</span>
            <span class="n">spec</span> <span class="o">=</span> <span class="p">(</span>
                <span class="bp">cls</span><span class="o">.</span><span class="n">import_nim_code</span><span class="p">(</span><span class="n">fullname</span><span class="p">,</span> <span class="n">path</span><span class="p">,</span> <span class="n">library</span><span class="o">=</span><span class="kc">False</span><span class="p">)</span>
                <span class="ow">or</span>
                <span class="bp">cls</span><span class="o">.</span><span class="n">import_nim_code</span><span class="p">(</span><span class="n">fullname</span><span class="p">,</span> <span class="n">path</span><span class="p">,</span> <span class="n">library</span><span class="o">=</span><span class="kc">True</span><span class="p">)</span>
            <span class="p">)</span>
        <span class="k">finally</span><span class="p">:</span>
            <span class="k">if</span> <span class="n">ignore_cache</span> <span class="o">!=</span> <span class="kc">None</span><span class="p">:</span>
                <span class="bp">cls</span><span class="o">.</span><span class="n">IGNORE_CACHE</span> <span class="o">=</span> <span class="n">tmp</span>

        <span class="k">if</span> <span class="ow">not</span> <span class="n">spec</span><span class="p">:</span>
            <span class="k">raise</span> <span class="ne">ImportError</span><span class="p">(</span><span class="sa">f</span><span class="s1">&#39;No module named </span><span class="si">{fullname}</span><span class="s1">&#39;</span><span class="p">)</span>

        <span class="n">module</span> <span class="o">=</span> <span class="n">spec</span><span class="o">.</span><span class="n">loader</span><span class="o">.</span><span class="n">create_module</span><span class="p">(</span><span class="n">spec</span><span class="p">)</span>
        <span class="k">return</span> <span class="n">module</span>

    <span class="nd">@classmethod</span>
    <span class="k">def</span> <span class="nf">import_nim_code</span><span class="p">(</span><span class="bp">cls</span><span class="p">,</span> <span class="n">fullname</span><span class="p">,</span> <span class="n">path</span><span class="p">,</span> <span class="o">*</span><span class="p">,</span> <span class="n">library</span><span class="p">:</span> <span class="nb">bool</span><span class="p">):</span>
        <span class="sd">&quot;&quot;&quot;</span>
<span class="sd">        Search for, compile, and return Spec for module loaders.</span>

<span class="sd">        Used by both NimModImporter and NimLibImporter for their Spec-finding</span>
<span class="sd">        capabilities.</span>

<span class="sd">        Args:</span>
<span class="sd">            fullname(str): the name given when importing the module in Python.</span>
<span class="sd">            path(list): additional search paths.</span>
<span class="sd">            library(bool): indicates whether or not to compile as a library.</span>

<span class="sd">        Returns:</span>
<span class="sd">            A Spec object that can be used to import the (now compiled) Nim</span>
<span class="sd">            module or library.</span>
<span class="sd">        &quot;&quot;&quot;</span>
        <span class="n">parts</span> <span class="o">=</span> <span class="n">fullname</span><span class="o">.</span><span class="n">split</span><span class="p">(</span><span class="s1">&#39;.&#39;</span><span class="p">)</span>
        <span class="n">module</span> <span class="o">=</span> <span class="n">parts</span><span class="p">[</span><span class="o">-</span><span class="mi">1</span><span class="p">]</span> <span class="k">if</span> <span class="n">library</span> <span class="k">else</span> <span class="n">parts</span><span class="o">.</span><span class="n">pop</span><span class="p">()</span>
        <span class="n">module_file</span> <span class="o">=</span> <span class="sa">f</span><span class="s1">&#39;</span><span class="si">{module}</span><span class="s1">.nim&#39;</span>
        <span class="n">path</span> <span class="o">=</span> <span class="nb">list</span><span class="p">(</span><span class="n">path</span><span class="p">)</span> <span class="k">if</span> <span class="n">path</span> <span class="k">else</span> <span class="p">[]</span>  <span class="c1"># Ensure that path is always a list</span>

        <span class="c1"># NOTE(pebaz): Package is different based only on `library`</span>
        <span class="n">package</span> <span class="o">=</span> <span class="s1">&#39;/&#39;</span><span class="o">.</span><span class="n">join</span><span class="p">(</span><span class="n">parts</span><span class="p">)</span>

        <span class="n">search_paths</span> <span class="o">=</span> <span class="p">{</span>
            <span class="n">Path</span><span class="p">(</span><span class="n">i</span><span class="p">)</span>
            <span class="k">for</span> <span class="n">i</span> <span class="ow">in</span> <span class="p">(</span><span class="n">path</span> <span class="o">+</span> <span class="n">sys</span><span class="o">.</span><span class="n">path</span> <span class="o">+</span> <span class="p">[</span><span class="s1">&#39;.&#39;</span><span class="p">])</span>
            <span class="k">if</span> <span class="n">Path</span><span class="p">(</span><span class="n">i</span><span class="p">)</span><span class="o">.</span><span class="n">is_dir</span><span class="p">()</span>
        <span class="p">}</span>

        <span class="k">for</span> <span class="n">search_path</span> <span class="ow">in</span> <span class="n">search_paths</span><span class="p">:</span>
            <span class="n">spath</span> <span class="o">=</span> <span class="p">(</span><span class="n">search_path</span> <span class="o">/</span> <span class="n">package</span><span class="p">)</span><span class="o">.</span><span class="n">resolve</span><span class="p">()</span>

            <span class="c1"># Derive module path regardless of library or module</span>

            <span class="k">if</span> <span class="n">library</span> <span class="ow">and</span> <span class="ow">not</span> <span class="nb">any</span><span class="p">(</span><span class="n">spath</span><span class="o">.</span><span class="n">glob</span><span class="p">(</span><span class="s1">&#39;*.nimble&#39;</span><span class="p">)):</span> <span class="k">continue</span>

            <span class="n">module_path</span> <span class="o">=</span> <span class="n">spath</span> <span class="o">/</span> <span class="n">module_file</span>

            <span class="k">if</span> <span class="ow">not</span> <span class="n">module_path</span><span class="o">.</span><span class="n">exists</span><span class="p">():</span> <span class="k">continue</span>

            <span class="n">build_artifact</span> <span class="o">=</span> <span class="n">NimCompiler</span><span class="o">.</span><span class="n">build_artifact</span><span class="p">(</span><span class="n">module_path</span><span class="p">)</span>

            <span class="k">if</span> <span class="bp">cls</span><span class="o">.</span><span class="n">should_compile</span><span class="p">(</span><span class="n">module_path</span><span class="p">):</span>
                <span class="n">NimCompiler</span><span class="o">.</span><span class="n">compile_nim_code</span><span class="p">(</span>
                    <span class="n">module_path</span><span class="o">.</span><span class="n">parent</span> <span class="k">if</span> <span class="n">library</span> <span class="k">else</span> <span class="n">module_path</span><span class="p">,</span>
                    <span class="n">build_artifact</span><span class="p">,</span>
                    <span class="n">library</span><span class="o">=</span><span class="n">library</span>
                <span class="p">)</span>

                <span class="bp">cls</span><span class="o">.</span><span class="n">update_hash</span><span class="p">(</span><span class="n">module_path</span><span class="p">)</span>
            
            <span class="k">return</span> <span class="n">util</span><span class="o">.</span><span class="n">spec_from_file_location</span><span class="p">(</span>
                <span class="n">fullname</span><span class="p">,</span>
                <span class="n">location</span><span class="o">=</span><span class="nb">str</span><span class="p">(</span><span class="n">build_artifact</span><span class="o">.</span><span class="n">absolute</span><span class="p">())</span>
            <span class="p">)</span>

    <span class="nd">@classmethod</span>
    <span class="k">def</span> <span class="nf">should_compile</span><span class="p">(</span><span class="bp">cls</span><span class="p">,</span> <span class="n">module_path</span><span class="p">):</span>
        <span class="sd">&quot;&quot;&quot;</span>
<span class="sd">        Determines if a module should be rebuilt using only the path to it.</span>

<span class="sd">        Factors included in the decision to compile a module include: </span>

<span class="sd">         * If `IGNORE_CACHE` is set</span>
<span class="sd">         * If the module has been modified since the last build</span>
<span class="sd">         * If the `__pycache__` directory does not exist</span>
<span class="sd">         * If there is no cached build artifact available in `__pycache__`</span>

<span class="sd">        Args:</span>
<span class="sd">            module_path(Path): the Nim module to potentially (re)compile.</span>

<span class="sd">        Returns:</span>
<span class="sd">            A bool indicating whether or not the module should be (re)built.</span>
<span class="sd">        &quot;&quot;&quot;</span>
        <span class="k">return</span> <span class="nb">any</span><span class="p">([</span>
            <span class="bp">cls</span><span class="o">.</span><span class="n">IGNORE_CACHE</span><span class="p">,</span>
            <span class="bp">cls</span><span class="o">.</span><span class="n">hash_changed</span><span class="p">(</span><span class="n">module_path</span><span class="p">),</span>
            <span class="ow">not</span> <span class="bp">cls</span><span class="o">.</span><span class="n">is_cache</span><span class="p">(</span><span class="n">module_path</span><span class="p">),</span>
            <span class="ow">not</span> <span class="bp">cls</span><span class="o">.</span><span class="n">is_built</span><span class="p">(</span><span class="n">module_path</span><span class="p">)</span>
        <span class="p">])</span>

    <span class="nd">@classmethod</span>
    <span class="k">def</span> <span class="nf">_find_extensions</span><span class="p">(</span><span class="bp">cls</span><span class="p">,</span> <span class="n">path</span><span class="p">,</span> <span class="n">exclude_dirs</span><span class="o">=</span><span class="nb">set</span><span class="p">()):</span>
        <span class="sd">&quot;&quot;&quot;</span>
<span class="sd">        Recurses through a given path to find all Nim modules or libraries.</span>

<span class="sd">        Args:</span>
<span class="sd">            path(Path): the path to begin recursing.</span>
<span class="sd">            exclude_dirs(list): the list of Paths to skip while searching.</span>

<span class="sd">        Returns:</span>
<span class="sd">            A list of Path objects. File Paths indicate a Nim Module. Folder</span>
<span class="sd">            Paths indicate Nim Libraries.</span>
<span class="sd">        &quot;&quot;&quot;</span>
        <span class="n">exclude_dirs</span> <span class="o">=</span> <span class="p">{</span><span class="n">p</span><span class="o">.</span><span class="n">expanduser</span><span class="p">()</span><span class="o">.</span><span class="n">absolute</span><span class="p">()</span> <span class="k">for</span> <span class="n">i</span> <span class="ow">in</span> <span class="n">exclude_dirs</span><span class="p">}</span>
        <span class="n">nim_exts</span> <span class="o">=</span> <span class="p">[]</span>

        <span class="k">for</span> <span class="n">item</span> <span class="ow">in</span> <span class="n">path</span><span class="o">.</span><span class="n">iterdir</span><span class="p">():</span>
            <span class="k">if</span> <span class="n">item</span><span class="o">.</span><span class="n">expanduser</span><span class="p">()</span><span class="o">.</span><span class="n">absolute</span><span class="p">()</span> <span class="ow">in</span> <span class="n">exclude_dirs</span><span class="p">:</span>
                <span class="k">continue</span>

            <span class="k">if</span> <span class="n">item</span><span class="o">.</span><span class="n">is_dir</span><span class="p">()</span> <span class="ow">and</span> <span class="nb">list</span><span class="p">(</span><span class="n">item</span><span class="o">.</span><span class="n">glob</span><span class="p">(</span><span class="s1">&#39;*.nimble&#39;</span><span class="p">)):</span>
                <span class="c1"># Treat directory as one single Extension</span>
                <span class="p">(</span><span class="n">nimble_file</span><span class="p">,)</span> <span class="o">=</span> <span class="n">item</span><span class="o">.</span><span class="n">glob</span><span class="p">(</span><span class="s1">&#39;*.nimble&#39;</span><span class="p">)</span>
                <span class="n">nim_file</span> <span class="o">=</span> <span class="n">nimble_file</span><span class="o">.</span><span class="n">parent</span> <span class="o">/</span> <span class="p">(</span><span class="n">nimble_file</span><span class="o">.</span><span class="n">stem</span> <span class="o">+</span> <span class="s1">&#39;.nim&#39;</span><span class="p">)</span>

                <span class="c1"># NOTE(pebaz): Folder must contain Nim file of exact same name.</span>
                <span class="k">if</span> <span class="n">nim_file</span><span class="o">.</span><span class="n">exists</span><span class="p">():</span>
                    <span class="n">nim_exts</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">item</span><span class="p">)</span>

            <span class="k">elif</span> <span class="n">item</span><span class="o">.</span><span class="n">is_dir</span><span class="p">():</span>
                <span class="c1"># Treat item as directory</span>
                <span class="n">nim_exts</span><span class="o">.</span><span class="n">extend</span><span class="p">(</span>
                    <span class="bp">cls</span><span class="o">.</span><span class="n">_find_extensions</span><span class="p">(</span><span class="n">item</span><span class="p">,</span> <span class="n">exclude_dirs</span><span class="o">=</span><span class="n">exclude_dirs</span><span class="p">)</span>
                <span class="p">)</span>

            <span class="k">elif</span> <span class="n">item</span><span class="o">.</span><span class="n">suffix</span> <span class="o">==</span> <span class="s1">&#39;.nim&#39;</span><span class="p">:</span>
                <span class="c1"># Treat item as a Nim Extension.</span>
                <span class="n">nim_exts</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">item</span><span class="p">)</span>

        <span class="k">return</span> <span class="n">nim_exts</span>

    <span class="nd">@classmethod</span>
    <span class="k">def</span> <span class="nf">_build_nim_extension</span><span class="p">(</span><span class="bp">cls</span><span class="p">,</span> <span class="n">path</span><span class="p">,</span> <span class="n">root</span><span class="p">):</span>
        <span class="sd">&quot;&quot;&quot;</span>
<span class="sd">        Convenience function to create an Extension object from a given path.</span>

<span class="sd">        Args:</span>
<span class="sd">            path(Path): the path to the Nim module/library.</span>
<span class="sd">            root(tuple): the namespace to add the Extension to.</span>

<span class="sd">        Returns:</span>
<span class="sd">            An Extension object representing the Nim module or library that has</span>
<span class="sd">            successfully be compiled to C.</span>
<span class="sd">        &quot;&quot;&quot;</span>
        <span class="k">return</span> <span class="n">NimCompiler</span><span class="o">.</span><span class="n">compile_nim_extension</span><span class="p">(</span>
            <span class="n">path</span><span class="p">,</span> <span class="n">root</span><span class="p">,</span> <span class="n">library</span><span class="o">=</span><span class="n">path</span><span class="o">.</span><span class="n">is_dir</span><span class="p">()</span>
        <span class="p">)</span>

    <span class="nd">@classmethod</span>
    <span class="k">def</span> <span class="nf">check_nim_extensions</span><span class="p">(</span><span class="bp">cls</span><span class="p">,</span> <span class="n">root</span><span class="p">):</span>
        <span class="sd">&quot;&quot;&quot;</span>
<span class="sd">        if not cls.check_nim_extensions(root):</span>
<span class="sd">            ...</span>
<span class="sd">        else:</span>
<span class="sd">            extensions = cls.get_nim_extensions(root)</span>
<span class="sd">        &quot;&quot;&quot;</span>
        <span class="k">return</span> <span class="p">(</span><span class="n">root</span> <span class="o">/</span> <span class="n">NimCompiler</span><span class="o">.</span><span class="n">EXT_DIR</span><span class="p">)</span><span class="o">.</span><span class="n">exists</span><span class="p">()</span>

    <span class="nd">@classmethod</span>
    <span class="k">def</span> <span class="nf">get_nim_extensions</span><span class="p">(</span><span class="bp">cls</span><span class="p">,</span> <span class="n">root</span><span class="p">):</span>
        <span class="sd">&quot;&quot;&quot;</span>
<span class="sd">        Convenience function to look for previously compiled Nim Extensions.</span>

<span class="sd">        When extensions are created, they are stored in the</span>
<span class="sd">        `&lt;root&gt;/build/nim-extensions` directory. The reason this is necessary is</span>
<span class="sd">        because `setup.py` runs the `setup()` function twice: once to gather</span>
<span class="sd">        info and once to actually compile/bundle everything. On the first pass,</span>
<span class="sd">        the extensions are compiled to C. On the second pass, they are compiled</span>
<span class="sd">        to Python-compatible shared objects.</span>

<span class="sd">        Args:</span>
<span class="sd">            root(Path): the root of the project.</span>

<span class="sd">        Returns:</span>
<span class="sd">            A list of Extensions that were compiled on the library maintainer&#39;s</span>
<span class="sd">            computer.</span>
<span class="sd">        &quot;&quot;&quot;</span>
        <span class="n">extension_dir</span> <span class="o">=</span> <span class="n">root</span> <span class="o">/</span> <span class="n">NimCompiler</span><span class="o">.</span><span class="n">EXT_DIR</span>
        <span class="k">assert</span> <span class="n">extension_dir</span><span class="o">.</span><span class="n">exists</span><span class="p">()</span>
        <span class="k">return</span> <span class="p">[</span>
            <span class="n">Extension</span><span class="p">(</span>
                <span class="n">name</span><span class="o">=</span><span class="n">extension</span><span class="o">.</span><span class="n">name</span><span class="p">,</span>
                <span class="n">sources</span><span class="o">=</span><span class="p">[</span><span class="nb">str</span><span class="p">(</span><span class="n">c</span><span class="o">.</span><span class="n">absolute</span><span class="p">())</span> <span class="k">for</span> <span class="n">c</span> <span class="ow">in</span> <span class="n">extension</span><span class="o">.</span><span class="n">glob</span><span class="p">(</span><span class="s1">&#39;*.c&#39;</span><span class="p">)],</span>
                <span class="n">include_dirs</span><span class="o">=</span><span class="p">[</span><span class="nb">str</span><span class="p">(</span><span class="n">extension</span><span class="o">.</span><span class="n">absolute</span><span class="p">())]</span>
            <span class="p">)</span>
            <span class="k">for</span> <span class="n">extension</span> <span class="ow">in</span> <span class="n">extension_dir</span><span class="o">.</span><span class="n">iterdir</span><span class="p">()</span>
        <span class="p">]</span>

    <span class="nd">@classmethod</span>
    <span class="k">def</span> <span class="nf">build_nim_extensions</span><span class="p">(</span><span class="bp">cls</span><span class="p">,</span> <span class="n">root</span><span class="o">=</span><span class="kc">None</span><span class="p">,</span> <span class="n">exclude_dirs</span><span class="o">=</span><span class="p">[]):</span>
        <span class="sd">&quot;&quot;&quot;</span>
<span class="sd">        Gathers all Nim Extensions by recursing through a Python project.</span>

<span class="sd">        Compiles Nim modules and libraries to C and creates Extensions from them</span>
<span class="sd">        for source, binary, or wheel distribution.</span>

<span class="sd">        Automatically recurses through the project directory to find all the Nim</span>
<span class="sd">        modules and Nim libraries.</span>

<span class="sd">        NOTE: Since this method is the only method that should be used by</span>
<span class="sd">        consumers of the Nimporter API, it has to do a couple of things:</span>

<span class="sd">        1. Build all Nim modules and libraries into C Extensions.</span>
<span class="sd">        2. Compile all C Extensions with a C compiler on an end-user&#39;s machine.</span>

<span class="sd">        Case 1 happens when creating a source or binary distribution. Also, this</span>
<span class="sd">        can happen if installing via: `python setup.py install` after cloning</span>
<span class="sd">        from Git.</span>

<span class="sd">        Case 2 happens after the C files have been put into the source archive</span>
<span class="sd">        and shipped to the end user. When the end user runs the `setup()`</span>
<span class="sd">        function, the already-bundled C files need to be compiled as Extensions</span>
<span class="sd">        rather than trying to look for Nim files that have not been bundled.</span>

<span class="sd">        Although this is a complicated process, it can be illustrated here:</span>

<span class="sd">        * `python setup.py install`: Case 1 + 2</span>
<span class="sd">        * `pip install some-lib`: Case 2</span>
<span class="sd">        * `pip install git+https://github.com/some-lib`: Case 1 + 2</span>

<span class="sd">        Args:</span>
<span class="sd">            root(tuple): the namespace to add all extensions to.</span>
<span class="sd">            exclude_dirs(list): the Paths to skip while recursing the project.</span>

<span class="sd">        Returns:</span>
<span class="sd">            A list of Extensions that can be added to the setup() function&#39;s</span>
<span class="sd">            &quot;ext_modules&quot; keyword argument.</span>
<span class="sd">        &quot;&quot;&quot;</span>
        <span class="c1">#root = (root or Path()).expanduser().absolute()</span>
        <span class="n">root</span> <span class="o">=</span> <span class="n">root</span> <span class="ow">or</span> <span class="n">Path</span><span class="p">()</span>

        <span class="c1"># Check for bundled C source files</span>
        <span class="k">if</span> <span class="bp">cls</span><span class="o">.</span><span class="n">check_nim_extensions</span><span class="p">(</span><span class="n">root</span><span class="p">):</span>

            <span class="c1"># NOTE(pebaz): Run only on end-user&#39;s machine.</span>
            <span class="k">return</span> <span class="bp">cls</span><span class="o">.</span><span class="n">get_nim_extensions</span><span class="p">(</span><span class="n">root</span><span class="p">)</span>

        <span class="n">extensions</span> <span class="o">=</span> <span class="p">[]</span>

        <span class="c1"># Create extensions from the Nim files found within the project</span>
        <span class="k">for</span> <span class="n">extension</span> <span class="ow">in</span> <span class="bp">cls</span><span class="o">.</span><span class="n">_find_extensions</span><span class="p">(</span><span class="n">root</span><span class="p">,</span> <span class="n">exclude_dirs</span><span class="p">):</span>

            <span class="c1"># NOTE(pebaz): Run on author&#39;s machine or when building from source</span>
            <span class="n">ext</span> <span class="o">=</span> <span class="bp">cls</span><span class="o">.</span><span class="n">_build_nim_extension</span><span class="p">(</span><span class="n">extension</span><span class="p">,</span> <span class="n">root</span><span class="p">)</span>
            <span class="k">if</span> <span class="n">ext</span><span class="p">:</span> <span class="n">extensions</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">ext</span><span class="p">)</span>

        <span class="k">return</span> <span class="n">extensions</span>
</pre></div>

  </div>
</div>


      <div class="class">
          <h3>Ancestors (in MRO)</h3>
          <ul class="class_list">
          <li><a href="#nimporter.Nimporter">Nimporter</a></li>
          <li>builtins.object</li>
          </ul>
          <h3>Class variables</h3>
            <div class="item">
            <p id="nimporter.Nimporter.IGNORE_CACHE" class="name">var <span class="ident">IGNORE_CACHE</span></p>
            

            
  
  <div class="source_cont">
</div>

            </div>
          <h3>Static methods</h3>
            
  <div class="item">
    <div class="name def" id="nimporter.Nimporter.hash_file">
    <p>def <span class="ident">hash_file</span>(</p><p>module_path)</p>
    </div>
    

    
  
    <div class="desc"><p>Convenience function to hash a given file.</p>
<p>Args:
    module_path(Path): the file to hash.</p>
<p>Returns:
    The hash bytes of the Nim file.</p></div>
  <div class="source_cont">
  <p class="source_link"><a href="javascript:void(0);" onclick="toggle('source-nimporter.Nimporter.hash_file', this);">Show source &equiv;</a></p>
  <div id="source-nimporter.Nimporter.hash_file" class="source">
    <div class="codehilite"><pre><span></span><span class="nd">@staticmethod</span>
<span class="k">def</span> <span class="nf">hash_file</span><span class="p">(</span><span class="n">module_path</span><span class="p">):</span>
    <span class="sd">&quot;&quot;&quot;</span>
<span class="sd">    Convenience function to hash a given file.</span>
<span class="sd">    Args:</span>
<span class="sd">        module_path(Path): the file to hash.</span>
<span class="sd">    </span>
<span class="sd">    Returns:</span>
<span class="sd">        The hash bytes of the Nim file.</span>
<span class="sd">    &quot;&quot;&quot;</span>
    <span class="n">block_size</span> <span class="o">=</span> <span class="mi">65536</span>
    <span class="n">hasher</span> <span class="o">=</span> <span class="n">hashlib</span><span class="o">.</span><span class="n">md5</span><span class="p">()</span>
    <span class="k">with</span> <span class="n">module_path</span><span class="o">.</span><span class="n">open</span><span class="p">(</span><span class="s1">&#39;rb&#39;</span><span class="p">)</span> <span class="k">as</span> <span class="n">file</span><span class="p">:</span>
        <span class="n">buf</span> <span class="o">=</span> <span class="n">file</span><span class="o">.</span><span class="n">read</span><span class="p">(</span><span class="n">block_size</span><span class="p">)</span>
        <span class="k">while</span> <span class="nb">len</span><span class="p">(</span><span class="n">buf</span><span class="p">)</span> <span class="o">&gt;</span> <span class="mi">0</span><span class="p">:</span>
            <span class="n">hasher</span><span class="o">.</span><span class="n">update</span><span class="p">(</span><span class="n">buf</span><span class="p">)</span>
            <span class="n">buf</span> <span class="o">=</span> <span class="n">file</span><span class="o">.</span><span class="n">read</span><span class="p">(</span><span class="n">block_size</span><span class="p">)</span>
    <span class="k">return</span> <span class="n">hasher</span><span class="o">.</span><span class="n">digest</span><span class="p">()</span>
</pre></div>

  </div>
</div>

  </div>
  
          <h3>Methods</h3>
            
  <div class="item">
    <div class="name def" id="nimporter.Nimporter.build_nim_extensions">
    <p>def <span class="ident">build_nim_extensions</span>(</p><p>cls, root=None, exclude_dirs=[])</p>
    </div>
    

    
  
    <div class="desc"><p>Gathers all Nim Extensions by recursing through a Python project.</p>
<p>Compiles Nim modules and libraries to C and creates Extensions from them
for source, binary, or wheel distribution.</p>
<p>Automatically recurses through the project directory to find all the Nim
modules and Nim libraries.</p>
<p>NOTE: Since this method is the only method that should be used by
consumers of the Nimporter API, it has to do a couple of things:</p>
<ol>
<li>Build all Nim modules and libraries into C Extensions.</li>
<li>Compile all C Extensions with a C compiler on an end-user's machine.</li>
</ol>
<p>Case 1 happens when creating a source or binary distribution. Also, this
can happen if installing via: <code>python setup.py install</code> after cloning
from Git.</p>
<p>Case 2 happens after the C files have been put into the source archive
and shipped to the end user. When the end user runs the <code>setup()</code>
function, the already-bundled C files need to be compiled as Extensions
rather than trying to look for Nim files that have not been bundled.</p>
<p>Although this is a complicated process, it can be illustrated here:</p>
<ul>
<li><code>python setup.py install</code>: Case 1 + 2</li>
<li><code>pip install some-lib</code>: Case 2</li>
<li><code>pip install git+https://github.com/some-lib</code>: Case 1 + 2</li>
</ul>
<p>Args:
    root(tuple): the namespace to add all extensions to.
    exclude_dirs(list): the Paths to skip while recursing the project.</p>
<p>Returns:
    A list of Extensions that can be added to the setup() function's
    "ext_modules" keyword argument.</p></div>
  <div class="source_cont">
  <p class="source_link"><a href="javascript:void(0);" onclick="toggle('source-nimporter.Nimporter.build_nim_extensions', this);">Show source &equiv;</a></p>
  <div id="source-nimporter.Nimporter.build_nim_extensions" class="source">
    <div class="codehilite"><pre><span></span><span class="nd">@classmethod</span>
<span class="k">def</span> <span class="nf">build_nim_extensions</span><span class="p">(</span><span class="bp">cls</span><span class="p">,</span> <span class="n">root</span><span class="o">=</span><span class="kc">None</span><span class="p">,</span> <span class="n">exclude_dirs</span><span class="o">=</span><span class="p">[]):</span>
    <span class="sd">&quot;&quot;&quot;</span>
<span class="sd">    Gathers all Nim Extensions by recursing through a Python project.</span>
<span class="sd">    Compiles Nim modules and libraries to C and creates Extensions from them</span>
<span class="sd">    for source, binary, or wheel distribution.</span>
<span class="sd">    Automatically recurses through the project directory to find all the Nim</span>
<span class="sd">    modules and Nim libraries.</span>
<span class="sd">    NOTE: Since this method is the only method that should be used by</span>
<span class="sd">    consumers of the Nimporter API, it has to do a couple of things:</span>
<span class="sd">    1. Build all Nim modules and libraries into C Extensions.</span>
<span class="sd">    2. Compile all C Extensions with a C compiler on an end-user&#39;s machine.</span>
<span class="sd">    Case 1 happens when creating a source or binary distribution. Also, this</span>
<span class="sd">    can happen if installing via: `python setup.py install` after cloning</span>
<span class="sd">    from Git.</span>
<span class="sd">    Case 2 happens after the C files have been put into the source archive</span>
<span class="sd">    and shipped to the end user. When the end user runs the `setup()`</span>
<span class="sd">    function, the already-bundled C files need to be compiled as Extensions</span>
<span class="sd">    rather than trying to look for Nim files that have not been bundled.</span>
<span class="sd">    Although this is a complicated process, it can be illustrated here:</span>
<span class="sd">    * `python setup.py install`: Case 1 + 2</span>
<span class="sd">    * `pip install some-lib`: Case 2</span>
<span class="sd">    * `pip install git+https://github.com/some-lib`: Case 1 + 2</span>
<span class="sd">    Args:</span>
<span class="sd">        root(tuple): the namespace to add all extensions to.</span>
<span class="sd">        exclude_dirs(list): the Paths to skip while recursing the project.</span>
<span class="sd">    Returns:</span>
<span class="sd">        A list of Extensions that can be added to the setup() function&#39;s</span>
<span class="sd">        &quot;ext_modules&quot; keyword argument.</span>
<span class="sd">    &quot;&quot;&quot;</span>
    <span class="c1">#root = (root or Path()).expanduser().absolute()</span>
    <span class="n">root</span> <span class="o">=</span> <span class="n">root</span> <span class="ow">or</span> <span class="n">Path</span><span class="p">()</span>
    <span class="c1"># Check for bundled C source files</span>
    <span class="k">if</span> <span class="bp">cls</span><span class="o">.</span><span class="n">check_nim_extensions</span><span class="p">(</span><span class="n">root</span><span class="p">):</span>
        <span class="c1"># NOTE(pebaz): Run only on end-user&#39;s machine.</span>
        <span class="k">return</span> <span class="bp">cls</span><span class="o">.</span><span class="n">get_nim_extensions</span><span class="p">(</span><span class="n">root</span><span class="p">)</span>
    <span class="n">extensions</span> <span class="o">=</span> <span class="p">[]</span>
    <span class="c1"># Create extensions from the Nim files found within the project</span>
    <span class="k">for</span> <span class="n">extension</span> <span class="ow">in</span> <span class="bp">cls</span><span class="o">.</span><span class="n">_find_extensions</span><span class="p">(</span><span class="n">root</span><span class="p">,</span> <span class="n">exclude_dirs</span><span class="p">):</span>
        <span class="c1"># NOTE(pebaz): Run on author&#39;s machine or when building from source</span>
        <span class="n">ext</span> <span class="o">=</span> <span class="bp">cls</span><span class="o">.</span><span class="n">_build_nim_extension</span><span class="p">(</span><span class="n">extension</span><span class="p">,</span> <span class="n">root</span><span class="p">)</span>
        <span class="k">if</span> <span class="n">ext</span><span class="p">:</span> <span class="n">extensions</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">ext</span><span class="p">)</span>
    <span class="k">return</span> <span class="n">extensions</span>
</pre></div>

  </div>
</div>

  </div>
  
            
  <div class="item">
    <div class="name def" id="nimporter.Nimporter.check_nim_extensions">
    <p>def <span class="ident">check_nim_extensions</span>(</p><p>cls, root)</p>
    </div>
    

    
  
    <div class="desc"><p>if not cls.check_nim_extensions(root):
    ...
else:
    extensions = cls.get_nim_extensions(root)</p></div>
  <div class="source_cont">
  <p class="source_link"><a href="javascript:void(0);" onclick="toggle('source-nimporter.Nimporter.check_nim_extensions', this);">Show source &equiv;</a></p>
  <div id="source-nimporter.Nimporter.check_nim_extensions" class="source">
    <div class="codehilite"><pre><span></span><span class="nd">@classmethod</span>
<span class="k">def</span> <span class="nf">check_nim_extensions</span><span class="p">(</span><span class="bp">cls</span><span class="p">,</span> <span class="n">root</span><span class="p">):</span>
    <span class="sd">&quot;&quot;&quot;</span>
<span class="sd">    if not cls.check_nim_extensions(root):</span>
<span class="sd">        ...</span>
<span class="sd">    else:</span>
<span class="sd">        extensions = cls.get_nim_extensions(root)</span>
<span class="sd">    &quot;&quot;&quot;</span>
    <span class="k">return</span> <span class="p">(</span><span class="n">root</span> <span class="o">/</span> <span class="n">NimCompiler</span><span class="o">.</span><span class="n">EXT_DIR</span><span class="p">)</span><span class="o">.</span><span class="n">exists</span><span class="p">()</span>
</pre></div>

  </div>
</div>

  </div>
  
            
  <div class="item">
    <div class="name def" id="nimporter.Nimporter.get_hash">
    <p>def <span class="ident">get_hash</span>(</p><p>cls, module_path)</p>
    </div>
    

    
  
    <div class="desc"><p>Gathers the hash for a given Nim module.</p>
<p>Args:
    module_path(Path): the Nim module for which to return its hash.</p>
<p>Raises:
    NimporterException: if the module has not yet been hashed.</p>
<p>Returns:
    The bytes of the hash for a given Nim module.</p></div>
  <div class="source_cont">
  <p class="source_link"><a href="javascript:void(0);" onclick="toggle('source-nimporter.Nimporter.get_hash', this);">Show source &equiv;</a></p>
  <div id="source-nimporter.Nimporter.get_hash" class="source">
    <div class="codehilite"><pre><span></span><span class="nd">@classmethod</span>
<span class="k">def</span> <span class="nf">get_hash</span><span class="p">(</span><span class="bp">cls</span><span class="p">,</span> <span class="n">module_path</span><span class="p">):</span>
    <span class="sd">&quot;&quot;&quot;</span>
<span class="sd">    Gathers the hash for a given Nim module.</span>
<span class="sd">    Args:</span>
<span class="sd">        module_path(Path): the Nim module for which to return its hash.</span>
<span class="sd">    Raises:</span>
<span class="sd">        NimporterException: if the module has not yet been hashed.</span>
<span class="sd">    Returns:</span>
<span class="sd">        The bytes of the hash for a given Nim module.</span>
<span class="sd">    &quot;&quot;&quot;</span>
    <span class="k">if</span> <span class="ow">not</span> <span class="bp">cls</span><span class="o">.</span><span class="n">is_hashed</span><span class="p">(</span><span class="n">module_path</span><span class="p">):</span>
        <span class="n">path</span> <span class="o">=</span> <span class="n">module_path</span><span class="o">.</span><span class="n">absolute</span><span class="p">()</span>
        <span class="k">raise</span> <span class="n">NimporterException</span><span class="p">(</span><span class="sa">f</span><span class="s1">&#39;Module </span><span class="si">{path}</span><span class="s1"> has not yet been hashed.&#39;</span><span class="p">)</span>
    <span class="k">return</span> <span class="bp">cls</span><span class="o">.</span><span class="n">hash_filename</span><span class="p">(</span><span class="n">module_path</span><span class="p">)</span><span class="o">.</span><span class="n">read_bytes</span><span class="p">()</span>
</pre></div>

  </div>
</div>

  </div>
  
            
  <div class="item">
    <div class="name def" id="nimporter.Nimporter.get_nim_extensions">
    <p>def <span class="ident">get_nim_extensions</span>(</p><p>cls, root)</p>
    </div>
    

    
  
    <div class="desc"><p>Convenience function to look for previously compiled Nim Extensions.</p>
<p>When extensions are created, they are stored in the
<code>&lt;root&gt;/build/nim-extensions</code> directory. The reason this is necessary is
because <code>setup.py</code> runs the <code>setup()</code> function twice: once to gather
info and once to actually compile/bundle everything. On the first pass,
the extensions are compiled to C. On the second pass, they are compiled
to Python-compatible shared objects.</p>
<p>Args:
    root(Path): the root of the project.</p>
<p>Returns:
    A list of Extensions that were compiled on the library maintainer's
    computer.</p></div>
  <div class="source_cont">
  <p class="source_link"><a href="javascript:void(0);" onclick="toggle('source-nimporter.Nimporter.get_nim_extensions', this);">Show source &equiv;</a></p>
  <div id="source-nimporter.Nimporter.get_nim_extensions" class="source">
    <div class="codehilite"><pre><span></span><span class="nd">@classmethod</span>
<span class="k">def</span> <span class="nf">get_nim_extensions</span><span class="p">(</span><span class="bp">cls</span><span class="p">,</span> <span class="n">root</span><span class="p">):</span>
    <span class="sd">&quot;&quot;&quot;</span>
<span class="sd">    Convenience function to look for previously compiled Nim Extensions.</span>
<span class="sd">    When extensions are created, they are stored in the</span>
<span class="sd">    `&lt;root&gt;/build/nim-extensions` directory. The reason this is necessary is</span>
<span class="sd">    because `setup.py` runs the `setup()` function twice: once to gather</span>
<span class="sd">    info and once to actually compile/bundle everything. On the first pass,</span>
<span class="sd">    the extensions are compiled to C. On the second pass, they are compiled</span>
<span class="sd">    to Python-compatible shared objects.</span>
<span class="sd">    Args:</span>
<span class="sd">        root(Path): the root of the project.</span>
<span class="sd">    Returns:</span>
<span class="sd">        A list of Extensions that were compiled on the library maintainer&#39;s</span>
<span class="sd">        computer.</span>
<span class="sd">    &quot;&quot;&quot;</span>
    <span class="n">extension_dir</span> <span class="o">=</span> <span class="n">root</span> <span class="o">/</span> <span class="n">NimCompiler</span><span class="o">.</span><span class="n">EXT_DIR</span>
    <span class="k">assert</span> <span class="n">extension_dir</span><span class="o">.</span><span class="n">exists</span><span class="p">()</span>
    <span class="k">return</span> <span class="p">[</span>
        <span class="n">Extension</span><span class="p">(</span>
            <span class="n">name</span><span class="o">=</span><span class="n">extension</span><span class="o">.</span><span class="n">name</span><span class="p">,</span>
            <span class="n">sources</span><span class="o">=</span><span class="p">[</span><span class="nb">str</span><span class="p">(</span><span class="n">c</span><span class="o">.</span><span class="n">absolute</span><span class="p">())</span> <span class="k">for</span> <span class="n">c</span> <span class="ow">in</span> <span class="n">extension</span><span class="o">.</span><span class="n">glob</span><span class="p">(</span><span class="s1">&#39;*.c&#39;</span><span class="p">)],</span>
            <span class="n">include_dirs</span><span class="o">=</span><span class="p">[</span><span class="nb">str</span><span class="p">(</span><span class="n">extension</span><span class="o">.</span><span class="n">absolute</span><span class="p">())]</span>
        <span class="p">)</span>
        <span class="k">for</span> <span class="n">extension</span> <span class="ow">in</span> <span class="n">extension_dir</span><span class="o">.</span><span class="n">iterdir</span><span class="p">()</span>
    <span class="p">]</span>
</pre></div>

  </div>
</div>

  </div>
  
            
  <div class="item">
    <div class="name def" id="nimporter.Nimporter.hash_changed">
    <p>def <span class="ident">hash_changed</span>(</p><p>cls, module_path)</p>
    </div>
    

    
  
    <div class="desc"><p>Determines if a module has been modified.</p>
<p>Args:
    module_path(Path): the Nim module to check for modification.</p>
<p>Returns:
    A bool indicating whether or not a given Nim file has changed since
    last hash. If the module has not yet been hashed, returns True.</p></div>
  <div class="source_cont">
  <p class="source_link"><a href="javascript:void(0);" onclick="toggle('source-nimporter.Nimporter.hash_changed', this);">Show source &equiv;</a></p>
  <div id="source-nimporter.Nimporter.hash_changed" class="source">
    <div class="codehilite"><pre><span></span><span class="nd">@classmethod</span>
<span class="k">def</span> <span class="nf">hash_changed</span><span class="p">(</span><span class="bp">cls</span><span class="p">,</span> <span class="n">module_path</span><span class="p">):</span>
    <span class="sd">&quot;&quot;&quot;</span>
<span class="sd">    Determines if a module has been modified.</span>
<span class="sd">    Args:</span>
<span class="sd">        module_path(Path): the Nim module to check for modification.</span>
<span class="sd">    Returns:</span>
<span class="sd">        A bool indicating whether or not a given Nim file has changed since</span>
<span class="sd">        last hash. If the module has not yet been hashed, returns True.</span>
<span class="sd">    &quot;&quot;&quot;</span>
    <span class="k">if</span> <span class="ow">not</span> <span class="bp">cls</span><span class="o">.</span><span class="n">is_hashed</span><span class="p">(</span><span class="n">module_path</span><span class="p">):</span>
        <span class="k">return</span> <span class="kc">True</span>
    <span class="k">return</span> <span class="bp">cls</span><span class="o">.</span><span class="n">get_hash</span><span class="p">(</span><span class="n">module_path</span><span class="p">)</span> <span class="o">!=</span> <span class="bp">cls</span><span class="o">.</span><span class="n">hash_file</span><span class="p">(</span><span class="n">module_path</span><span class="p">)</span>
</pre></div>

  </div>
</div>

  </div>
  
            
  <div class="item">
    <div class="name def" id="nimporter.Nimporter.hash_filename">
    <p>def <span class="ident">hash_filename</span>(</p><p>cls, module_path)</p>
    </div>
    

    
  
    <div class="desc"><p>Gets the filename that should contain a given module's hash.</p>
<p>Args:
    module_path(Path): the Nim module the hash file pertains to.</p>
<p>Returns:
    The hash filename as a Path.</p></div>
  <div class="source_cont">
  <p class="source_link"><a href="javascript:void(0);" onclick="toggle('source-nimporter.Nimporter.hash_filename', this);">Show source &equiv;</a></p>
  <div id="source-nimporter.Nimporter.hash_filename" class="source">
    <div class="codehilite"><pre><span></span><span class="nd">@classmethod</span>
<span class="k">def</span> <span class="nf">hash_filename</span><span class="p">(</span><span class="bp">cls</span><span class="p">,</span> <span class="n">module_path</span><span class="p">):</span>
    <span class="sd">&quot;&quot;&quot;</span>
<span class="sd">    Gets the filename that should contain a given module&#39;s hash.</span>

<span class="sd">    Args:</span>
<span class="sd">        module_path(Path): the Nim module the hash file pertains to.</span>
<span class="sd">    Returns:</span>
<span class="sd">        The hash filename as a Path.</span>
<span class="sd">    &quot;&quot;&quot;</span>
    <span class="k">return</span> <span class="p">(</span>
        <span class="n">NimCompiler</span><span class="o">.</span><span class="n">pycache_dir</span><span class="p">(</span><span class="n">module_path</span><span class="p">)</span> <span class="o">/</span> <span class="p">(</span><span class="n">module_path</span><span class="o">.</span><span class="n">name</span> <span class="o">+</span> <span class="s1">&#39;.hash&#39;</span><span class="p">)</span>
    <span class="p">)</span>
</pre></div>

  </div>
</div>

  </div>
  
            
  <div class="item">
    <div class="name def" id="nimporter.Nimporter.import_nim_code">
    <p>def <span class="ident">import_nim_code</span>(</p><p>cls, fullname, path)</p>
    </div>
    

    
  
    <div class="desc"><p>Search for, compile, and return Spec for module loaders.</p>
<p>Used by both NimModImporter and NimLibImporter for their Spec-finding
capabilities.</p>
<p>Args:
    fullname(str): the name given when importing the module in Python.
    path(list): additional search paths.
    library(bool): indicates whether or not to compile as a library.</p>
<p>Returns:
    A Spec object that can be used to import the (now compiled) Nim
    module or library.</p></div>
  <div class="source_cont">
  <p class="source_link"><a href="javascript:void(0);" onclick="toggle('source-nimporter.Nimporter.import_nim_code', this);">Show source &equiv;</a></p>
  <div id="source-nimporter.Nimporter.import_nim_code" class="source">
    <div class="codehilite"><pre><span></span><span class="nd">@classmethod</span>
<span class="k">def</span> <span class="nf">import_nim_code</span><span class="p">(</span><span class="bp">cls</span><span class="p">,</span> <span class="n">fullname</span><span class="p">,</span> <span class="n">path</span><span class="p">,</span> <span class="o">*</span><span class="p">,</span> <span class="n">library</span><span class="p">:</span> <span class="nb">bool</span><span class="p">):</span>
    <span class="sd">&quot;&quot;&quot;</span>
<span class="sd">    Search for, compile, and return Spec for module loaders.</span>
<span class="sd">    Used by both NimModImporter and NimLibImporter for their Spec-finding</span>
<span class="sd">    capabilities.</span>
<span class="sd">    Args:</span>
<span class="sd">        fullname(str): the name given when importing the module in Python.</span>
<span class="sd">        path(list): additional search paths.</span>
<span class="sd">        library(bool): indicates whether or not to compile as a library.</span>
<span class="sd">    Returns:</span>
<span class="sd">        A Spec object that can be used to import the (now compiled) Nim</span>
<span class="sd">        module or library.</span>
<span class="sd">    &quot;&quot;&quot;</span>
    <span class="n">parts</span> <span class="o">=</span> <span class="n">fullname</span><span class="o">.</span><span class="n">split</span><span class="p">(</span><span class="s1">&#39;.&#39;</span><span class="p">)</span>
    <span class="n">module</span> <span class="o">=</span> <span class="n">parts</span><span class="p">[</span><span class="o">-</span><span class="mi">1</span><span class="p">]</span> <span class="k">if</span> <span class="n">library</span> <span class="k">else</span> <span class="n">parts</span><span class="o">.</span><span class="n">pop</span><span class="p">()</span>
    <span class="n">module_file</span> <span class="o">=</span> <span class="sa">f</span><span class="s1">&#39;</span><span class="si">{module}</span><span class="s1">.nim&#39;</span>
    <span class="n">path</span> <span class="o">=</span> <span class="nb">list</span><span class="p">(</span><span class="n">path</span><span class="p">)</span> <span class="k">if</span> <span class="n">path</span> <span class="k">else</span> <span class="p">[]</span>  <span class="c1"># Ensure that path is always a list</span>
    <span class="c1"># NOTE(pebaz): Package is different based only on `library`</span>
    <span class="n">package</span> <span class="o">=</span> <span class="s1">&#39;/&#39;</span><span class="o">.</span><span class="n">join</span><span class="p">(</span><span class="n">parts</span><span class="p">)</span>
    <span class="n">search_paths</span> <span class="o">=</span> <span class="p">{</span>
        <span class="n">Path</span><span class="p">(</span><span class="n">i</span><span class="p">)</span>
        <span class="k">for</span> <span class="n">i</span> <span class="ow">in</span> <span class="p">(</span><span class="n">path</span> <span class="o">+</span> <span class="n">sys</span><span class="o">.</span><span class="n">path</span> <span class="o">+</span> <span class="p">[</span><span class="s1">&#39;.&#39;</span><span class="p">])</span>
        <span class="k">if</span> <span class="n">Path</span><span class="p">(</span><span class="n">i</span><span class="p">)</span><span class="o">.</span><span class="n">is_dir</span><span class="p">()</span>
    <span class="p">}</span>
    <span class="k">for</span> <span class="n">search_path</span> <span class="ow">in</span> <span class="n">search_paths</span><span class="p">:</span>
        <span class="n">spath</span> <span class="o">=</span> <span class="p">(</span><span class="n">search_path</span> <span class="o">/</span> <span class="n">package</span><span class="p">)</span><span class="o">.</span><span class="n">resolve</span><span class="p">()</span>
        <span class="c1"># Derive module path regardless of library or module</span>
        <span class="k">if</span> <span class="n">library</span> <span class="ow">and</span> <span class="ow">not</span> <span class="nb">any</span><span class="p">(</span><span class="n">spath</span><span class="o">.</span><span class="n">glob</span><span class="p">(</span><span class="s1">&#39;*.nimble&#39;</span><span class="p">)):</span> <span class="k">continue</span>
        <span class="n">module_path</span> <span class="o">=</span> <span class="n">spath</span> <span class="o">/</span> <span class="n">module_file</span>
        <span class="k">if</span> <span class="ow">not</span> <span class="n">module_path</span><span class="o">.</span><span class="n">exists</span><span class="p">():</span> <span class="k">continue</span>
        <span class="n">build_artifact</span> <span class="o">=</span> <span class="n">NimCompiler</span><span class="o">.</span><span class="n">build_artifact</span><span class="p">(</span><span class="n">module_path</span><span class="p">)</span>
        <span class="k">if</span> <span class="bp">cls</span><span class="o">.</span><span class="n">should_compile</span><span class="p">(</span><span class="n">module_path</span><span class="p">):</span>
            <span class="n">NimCompiler</span><span class="o">.</span><span class="n">compile_nim_code</span><span class="p">(</span>
                <span class="n">module_path</span><span class="o">.</span><span class="n">parent</span> <span class="k">if</span> <span class="n">library</span> <span class="k">else</span> <span class="n">module_path</span><span class="p">,</span>
                <span class="n">build_artifact</span><span class="p">,</span>
                <span class="n">library</span><span class="o">=</span><span class="n">library</span>
            <span class="p">)</span>
            <span class="bp">cls</span><span class="o">.</span><span class="n">update_hash</span><span class="p">(</span><span class="n">module_path</span><span class="p">)</span>
        
        <span class="k">return</span> <span class="n">util</span><span class="o">.</span><span class="n">spec_from_file_location</span><span class="p">(</span>
            <span class="n">fullname</span><span class="p">,</span>
            <span class="n">location</span><span class="o">=</span><span class="nb">str</span><span class="p">(</span><span class="n">build_artifact</span><span class="o">.</span><span class="n">absolute</span><span class="p">())</span>
        <span class="p">)</span>
</pre></div>

  </div>
</div>

  </div>
  
            
  <div class="item">
    <div class="name def" id="nimporter.Nimporter.import_nim_module">
    <p>def <span class="ident">import_nim_module</span>(</p><p>cls, fullname, path=None, ignore_cache=None)</p>
    </div>
    

    
  
    <div class="desc"><p>Convenience function to manually import a given Nim module or library.</p>
<p>Can be used to explicitly import a module rather than using the <code>import</code>
keyword. Allows the cache to be ignored to solve issues arising from
caching one module when 10 other imported Nim libraries have changed.</p>
<p>Example Use:</p>
<div class="codehilite"><pre><span></span><span class="c1"># Rather than:</span>
<span class="kn">import</span> <span class="nn">foo</span>
<span class="c1"># You can say:</span>
<span class="n">foo</span> <span class="o">=</span> <span class="n">Nimporter</span><span class="o">.</span><span class="n">import_nim_module</span><span class="p">(</span><span class="s1">&#39;foo&#39;</span><span class="p">,</span> <span class="p">[</span><span class="s1">&#39;/some/random/dir&#39;</span><span class="p">])</span>
</pre></div>


<p>Args:
    fullname(str): the module to import. Can be 'foo' or 'foo.bar.baz'
    path(list): a list of paths to search first.
    ignore_cache(bool): whether or not to use a cached build if found.</p>
<p>Returns:
    The Python Module object representing the imported PYD or SO file.</p></div>
  <div class="source_cont">
  <p class="source_link"><a href="javascript:void(0);" onclick="toggle('source-nimporter.Nimporter.import_nim_module', this);">Show source &equiv;</a></p>
  <div id="source-nimporter.Nimporter.import_nim_module" class="source">
    <div class="codehilite"><pre><span></span><span class="nd">@classmethod</span>
<span class="k">def</span> <span class="nf">import_nim_module</span><span class="p">(</span><span class="bp">cls</span><span class="p">,</span> <span class="n">fullname</span><span class="p">,</span> <span class="n">path</span><span class="p">:</span><span class="nb">list</span><span class="o">=</span><span class="kc">None</span><span class="p">,</span> <span class="n">ignore_cache</span><span class="o">=</span><span class="kc">None</span><span class="p">):</span>
    <span class="sd">&quot;&quot;&quot;</span>
<span class="sd">    Convenience function to manually import a given Nim module or library.</span>
<span class="sd">    Can be used to explicitly import a module rather than using the `import`</span>
<span class="sd">    keyword. Allows the cache to be ignored to solve issues arising from</span>
<span class="sd">    caching one module when 10 other imported Nim libraries have changed.</span>
<span class="sd">    Example Use:</span>
<span class="sd">        # Rather than:</span>
<span class="sd">        import foo</span>
<span class="sd">        # You can say:</span>
<span class="sd">        foo = Nimporter.import_nim_module(&#39;foo&#39;, [&#39;/some/random/dir&#39;])</span>
<span class="sd">    Args:</span>
<span class="sd">        fullname(str): the module to import. Can be &#39;foo&#39; or &#39;foo.bar.baz&#39;</span>
<span class="sd">        path(list): a list of paths to search first.</span>
<span class="sd">        ignore_cache(bool): whether or not to use a cached build if found.</span>
<span class="sd">    Returns:</span>
<span class="sd">        The Python Module object representing the imported PYD or SO file.            </span>
<span class="sd">    &quot;&quot;&quot;</span>
    <span class="k">if</span> <span class="n">ignore_cache</span> <span class="o">!=</span> <span class="kc">None</span><span class="p">:</span>
        <span class="n">tmp</span> <span class="o">=</span> <span class="bp">cls</span><span class="o">.</span><span class="n">IGNORE_CACHE</span>
        <span class="bp">cls</span><span class="o">.</span><span class="n">IGNORE_CACHE</span> <span class="o">=</span> <span class="n">ignore_cache</span>
    <span class="k">try</span><span class="p">:</span>
        <span class="n">spec</span> <span class="o">=</span> <span class="p">(</span>
            <span class="bp">cls</span><span class="o">.</span><span class="n">import_nim_code</span><span class="p">(</span><span class="n">fullname</span><span class="p">,</span> <span class="n">path</span><span class="p">,</span> <span class="n">library</span><span class="o">=</span><span class="kc">False</span><span class="p">)</span>
            <span class="ow">or</span>
            <span class="bp">cls</span><span class="o">.</span><span class="n">import_nim_code</span><span class="p">(</span><span class="n">fullname</span><span class="p">,</span> <span class="n">path</span><span class="p">,</span> <span class="n">library</span><span class="o">=</span><span class="kc">True</span><span class="p">)</span>
        <span class="p">)</span>
    <span class="k">finally</span><span class="p">:</span>
        <span class="k">if</span> <span class="n">ignore_cache</span> <span class="o">!=</span> <span class="kc">None</span><span class="p">:</span>
            <span class="bp">cls</span><span class="o">.</span><span class="n">IGNORE_CACHE</span> <span class="o">=</span> <span class="n">tmp</span>
    <span class="k">if</span> <span class="ow">not</span> <span class="n">spec</span><span class="p">:</span>
        <span class="k">raise</span> <span class="ne">ImportError</span><span class="p">(</span><span class="sa">f</span><span class="s1">&#39;No module named </span><span class="si">{fullname}</span><span class="s1">&#39;</span><span class="p">)</span>
    <span class="n">module</span> <span class="o">=</span> <span class="n">spec</span><span class="o">.</span><span class="n">loader</span><span class="o">.</span><span class="n">create_module</span><span class="p">(</span><span class="n">spec</span><span class="p">)</span>
    <span class="k">return</span> <span class="n">module</span>
</pre></div>

  </div>
</div>

  </div>
  
            
  <div class="item">
    <div class="name def" id="nimporter.Nimporter.is_built">
    <p>def <span class="ident">is_built</span>(</p><p>cls, module_path)</p>
    </div>
    

    
  
    <div class="desc"><p>Determines if a given Nim module has already been built.</p>
<p>Args:
    module_path(Path): the Nim module for which to query for artifacts.</p>
<p>Returns:
    A bool indicating whether or not a given Nim file has already been
    built.</p></div>
  <div class="source_cont">
  <p class="source_link"><a href="javascript:void(0);" onclick="toggle('source-nimporter.Nimporter.is_built', this);">Show source &equiv;</a></p>
  <div id="source-nimporter.Nimporter.is_built" class="source">
    <div class="codehilite"><pre><span></span><span class="nd">@classmethod</span>
<span class="k">def</span> <span class="nf">is_built</span><span class="p">(</span><span class="bp">cls</span><span class="p">,</span> <span class="n">module_path</span><span class="p">):</span>
    <span class="sd">&quot;&quot;&quot;</span>
<span class="sd">    Determines if a given Nim module has already been built.</span>
<span class="sd">    Args:</span>
<span class="sd">        module_path(Path): the Nim module for which to query for artifacts.</span>
<span class="sd">    Returns:</span>
<span class="sd">        A bool indicating whether or not a given Nim file has already been</span>
<span class="sd">        built.</span>
<span class="sd">    &quot;&quot;&quot;</span>
    <span class="k">return</span> <span class="n">NimCompiler</span><span class="o">.</span><span class="n">build_artifact</span><span class="p">(</span><span class="n">module_path</span><span class="p">)</span><span class="o">.</span><span class="n">exists</span><span class="p">()</span>
</pre></div>

  </div>
</div>

  </div>
  
            
  <div class="item">
    <div class="name def" id="nimporter.Nimporter.is_cache">
    <p>def <span class="ident">is_cache</span>(</p><p>cls, module_path)</p>
    </div>
    

    
  
    <div class="desc"><p>Determines if the <code>__pycache__</code> dir for a given Nim module exists.</p>
<p>Args:
    module_path(Path): the Nim module the <code>__pycache__</code> dir pertains to.</p>
<p>Returns:
    A bool indicating whether or not a <strong>pycache</strong> directory exists to
    store hashes and build artifacts.</p></div>
  <div class="source_cont">
  <p class="source_link"><a href="javascript:void(0);" onclick="toggle('source-nimporter.Nimporter.is_cache', this);">Show source &equiv;</a></p>
  <div id="source-nimporter.Nimporter.is_cache" class="source">
    <div class="codehilite"><pre><span></span><span class="nd">@classmethod</span>
<span class="k">def</span> <span class="nf">is_cache</span><span class="p">(</span><span class="bp">cls</span><span class="p">,</span> <span class="n">module_path</span><span class="p">):</span>
    <span class="sd">&quot;&quot;&quot;</span>
<span class="sd">    Determines if the `__pycache__` dir for a given Nim module exists.</span>
<span class="sd">    Args:</span>
<span class="sd">        module_path(Path): the Nim module the `__pycache__` dir pertains to.</span>
<span class="sd">    Returns:</span>
<span class="sd">        A bool indicating whether or not a __pycache__ directory exists to</span>
<span class="sd">        store hashes and build artifacts.</span>
<span class="sd">    &quot;&quot;&quot;</span>
    <span class="k">return</span> <span class="n">NimCompiler</span><span class="o">.</span><span class="n">pycache_dir</span><span class="p">(</span><span class="n">module_path</span><span class="p">)</span><span class="o">.</span><span class="n">exists</span><span class="p">()</span>
</pre></div>

  </div>
</div>

  </div>
  
            
  <div class="item">
    <div class="name def" id="nimporter.Nimporter.is_hashed">
    <p>def <span class="ident">is_hashed</span>(</p><p>cls, module_path)</p>
    </div>
    

    
  
    <div class="desc"><p>Determines if a given Nim module has already been hashed.</p>
<p>Args:
    module_path(Path): the Nim module for which to query hash existence.</p>
<p>Returns:
    A bool indicating whether or not a given Nim file has already been
    hashed.</p></div>
  <div class="source_cont">
  <p class="source_link"><a href="javascript:void(0);" onclick="toggle('source-nimporter.Nimporter.is_hashed', this);">Show source &equiv;</a></p>
  <div id="source-nimporter.Nimporter.is_hashed" class="source">
    <div class="codehilite"><pre><span></span><span class="nd">@classmethod</span>
<span class="k">def</span> <span class="nf">is_hashed</span><span class="p">(</span><span class="bp">cls</span><span class="p">,</span> <span class="n">module_path</span><span class="p">):</span>
    <span class="sd">&quot;&quot;&quot;</span>
<span class="sd">    Determines if a given Nim module has already been hashed.</span>
<span class="sd">    Args:</span>
<span class="sd">        module_path(Path): the Nim module for which to query hash existence.</span>
<span class="sd">    Returns:</span>
<span class="sd">        A bool indicating whether or not a given Nim file has already been</span>
<span class="sd">        hashed.</span>
<span class="sd">    &quot;&quot;&quot;</span>
    <span class="k">return</span> <span class="bp">cls</span><span class="o">.</span><span class="n">hash_filename</span><span class="p">(</span><span class="n">module_path</span><span class="p">)</span><span class="o">.</span><span class="n">exists</span><span class="p">()</span>
</pre></div>

  </div>
</div>

  </div>
  
            
  <div class="item">
    <div class="name def" id="nimporter.Nimporter.should_compile">
    <p>def <span class="ident">should_compile</span>(</p><p>cls, module_path)</p>
    </div>
    

    
  
    <div class="desc"><p>Determines if a module should be rebuilt using only the path to it.</p>
<p>Factors included in the decision to compile a module include: </p>
<ul>
<li>If <code>IGNORE_CACHE</code> is set</li>
<li>If the module has been modified since the last build</li>
<li>If the <code>__pycache__</code> directory does not exist</li>
<li>If there is no cached build artifact available in <code>__pycache__</code></li>
</ul>
<p>Args:
    module_path(Path): the Nim module to potentially (re)compile.</p>
<p>Returns:
    A bool indicating whether or not the module should be (re)built.</p></div>
  <div class="source_cont">
  <p class="source_link"><a href="javascript:void(0);" onclick="toggle('source-nimporter.Nimporter.should_compile', this);">Show source &equiv;</a></p>
  <div id="source-nimporter.Nimporter.should_compile" class="source">
    <div class="codehilite"><pre><span></span><span class="nd">@classmethod</span>
<span class="k">def</span> <span class="nf">should_compile</span><span class="p">(</span><span class="bp">cls</span><span class="p">,</span> <span class="n">module_path</span><span class="p">):</span>
    <span class="sd">&quot;&quot;&quot;</span>
<span class="sd">    Determines if a module should be rebuilt using only the path to it.</span>
<span class="sd">    Factors included in the decision to compile a module include: </span>
<span class="sd">     * If `IGNORE_CACHE` is set</span>
<span class="sd">     * If the module has been modified since the last build</span>
<span class="sd">     * If the `__pycache__` directory does not exist</span>
<span class="sd">     * If there is no cached build artifact available in `__pycache__`</span>
<span class="sd">    Args:</span>
<span class="sd">        module_path(Path): the Nim module to potentially (re)compile.</span>
<span class="sd">    Returns:</span>
<span class="sd">        A bool indicating whether or not the module should be (re)built.</span>
<span class="sd">    &quot;&quot;&quot;</span>
    <span class="k">return</span> <span class="nb">any</span><span class="p">([</span>
        <span class="bp">cls</span><span class="o">.</span><span class="n">IGNORE_CACHE</span><span class="p">,</span>
        <span class="bp">cls</span><span class="o">.</span><span class="n">hash_changed</span><span class="p">(</span><span class="n">module_path</span><span class="p">),</span>
        <span class="ow">not</span> <span class="bp">cls</span><span class="o">.</span><span class="n">is_cache</span><span class="p">(</span><span class="n">module_path</span><span class="p">),</span>
        <span class="ow">not</span> <span class="bp">cls</span><span class="o">.</span><span class="n">is_built</span><span class="p">(</span><span class="n">module_path</span><span class="p">)</span>
    <span class="p">])</span>
</pre></div>

  </div>
</div>

  </div>
  
            
  <div class="item">
    <div class="name def" id="nimporter.Nimporter.update_hash">
    <p>def <span class="ident">update_hash</span>(</p><p>cls, module_path)</p>
    </div>
    

    
  
    <div class="desc"><p>Updates the hash file associated with a given Nim module.</p>
<p>This is commonly done after compilation to determine if recompilation is
required upon subsequent imports. If the module's hash file has not yet
been created, this method will create it and store it in the
<code>__pycache__</code> dir for the module.</p>
<p>Args:
    module_path(Path): the module which should have its hash updated.</p></div>
  <div class="source_cont">
  <p class="source_link"><a href="javascript:void(0);" onclick="toggle('source-nimporter.Nimporter.update_hash', this);">Show source &equiv;</a></p>
  <div id="source-nimporter.Nimporter.update_hash" class="source">
    <div class="codehilite"><pre><span></span><span class="nd">@classmethod</span>
<span class="k">def</span> <span class="nf">update_hash</span><span class="p">(</span><span class="bp">cls</span><span class="p">,</span> <span class="n">module_path</span><span class="p">):</span>
    <span class="sd">&quot;&quot;&quot;</span>
<span class="sd">    Updates the hash file associated with a given Nim module.</span>
<span class="sd">    This is commonly done after compilation to determine if recompilation is</span>
<span class="sd">    required upon subsequent imports. If the module&#39;s hash file has not yet</span>
<span class="sd">    been created, this method will create it and store it in the</span>
<span class="sd">    `__pycache__` dir for the module.</span>
<span class="sd">    Args:</span>
<span class="sd">        module_path(Path): the module which should have its hash updated.</span>
<span class="sd">    &quot;&quot;&quot;</span>
    <span class="n">hash_file</span> <span class="o">=</span> <span class="bp">cls</span><span class="o">.</span><span class="n">hash_filename</span><span class="p">(</span><span class="n">module_path</span><span class="p">)</span>
    <span class="n">hash_file</span><span class="o">.</span><span class="n">parent</span><span class="o">.</span><span class="n">mkdir</span><span class="p">(</span><span class="n">parents</span><span class="o">=</span><span class="kc">True</span><span class="p">,</span> <span class="n">exist_ok</span><span class="o">=</span><span class="kc">True</span><span class="p">)</span>
    <span class="k">with</span> <span class="n">hash_file</span><span class="o">.</span><span class="n">open</span><span class="p">(</span><span class="s1">&#39;wb&#39;</span><span class="p">)</span> <span class="k">as</span> <span class="n">file</span><span class="p">:</span>
        <span class="n">file</span><span class="o">.</span><span class="n">write</span><span class="p">(</span><span class="bp">cls</span><span class="o">.</span><span class="n">hash_file</span><span class="p">(</span><span class="n">module_path</span><span class="p">))</span>
</pre></div>

  </div>
</div>

  </div>
  
      </div>
      </div>
      
      <div class="item">
      <p id="nimporter.NimporterException" class="name">class <span class="ident">NimporterException</span></p>
      
  
    <div class="desc"><p>Catch-all for Nimporter exceptions</p></div>
  <div class="source_cont">
  <p class="source_link"><a href="javascript:void(0);" onclick="toggle('source-nimporter.NimporterException', this);">Show source &equiv;</a></p>
  <div id="source-nimporter.NimporterException" class="source">
    <div class="codehilite"><pre><span></span><span class="k">class</span> <span class="nc">NimporterException</span><span class="p">(</span><span class="ne">Exception</span><span class="p">):</span>
    <span class="s2">&quot;Catch-all for Nimporter exceptions&quot;</span>
</pre></div>

  </div>
</div>


      <div class="class">
          <h3>Ancestors (in MRO)</h3>
          <ul class="class_list">
          <li><a href="#nimporter.NimporterException">NimporterException</a></li>
          <li>builtins.Exception</li>
          <li>builtins.BaseException</li>
          <li>builtins.object</li>
          </ul>
          <h3>Class variables</h3>
            <div class="item">
            <p id="nimporter.NimporterException.args" class="name">var <span class="ident">args</span></p>
            

            
  
  <div class="source_cont">
</div>

            </div>
      </div>
      </div>

  </section>

    </article>
  <div class="clear"> </div>
  <footer id="footer">
    <p>
      Documentation generated by
      <a href="https://github.com/BurntSushi/pdoc">pdoc 0.3.2</a>
    </p>

    <p>pdoc is in the public domain with the
      <a href="http://unlicense.org">UNLICENSE</a></p>

    <p>Design by <a href="http://nadh.in">Kailash Nadh</a></p>
  </footer>
</div>
</body>
</html>
